Java高级开发之反射专题之Class类的使用

首先我们要知道,在面向对象的世界里,万事万物皆对象,所有的类都是java.lang.class的实例对象,所以就有了class的使用,废话不多,直接上代码。(由于代码中写了大量注释,就不在进行过多的解释,当然有小伙伴可能注释也看不懂,所以我在博客最下面补充了一些方法使用的解释。)

package reflect;

public class ClassDemo1 {
	public static void main(String[] args) {
		//Hrw的实例对象如何表示
		Hrw hrw = new Hrw();//hrw就表示出来了
		//Hrw这个类,也是一个实例对象,就是class对象
		//任何一个类都是class的实例对象,这个实例对象有三种表达方式
		
		//第一种表达方式》》》实际是在告诉我们任何一个类都有 一个隐含的静态成员变量class
		Class class1 = Hrw.class;
		//第二种表达方式,已经知道该类的对象通过getclass方法
		Class class2 = hrw.getClass();
		
		//class1 class2 表示了Hrw类的类类型(class type)
		//万事万物皆对象,类都是class类的对象。同时这个类我们称之为类的类类型
		
		//不管class1 和 class2都表示了Hrw类的类类型,一个类只可能是class类的一个实例对象
		System.out.println(class1 == class2);
		
		//第三种表达方式
		Class class3 = null;
		try {
			class3 = Class.forName("reflect");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println(class2 == class3);
		//我们可以通过类的类类型创建该类的实例对象》》》即我们可以通过class1,2,3来创建Hrw的实例对象
		try {
			Hrw hrw1 = (Hrw)class1.newInstance();//前提是要有无参数的构造方法
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} 
	}
}
class Hrw{}

    下面是结果

                                                 

由运行结果可知,class1 or  class2  or  class3都是一样的,这也就说明了通过类的类类型实例化和由类实例化是一样的。

可能有小伙伴又对newinstance()这个方法不懂啦,下面我进行简单的介绍

1.在初始化一个类,生成一个实例的时候;newInstance() 和 new 有什么区别?(Java面试题,需要面试的小伙伴记得关注哦)

用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。
Java中工厂模式经常使用newInstance来创建对象,因此从为什么要使用工厂模式上也可以找到具体答案。
例如:
Class c = Class.forName(“A”);factory = (AInterface)c.newInstance();
其中AInterface是A的接口,如果下面这样写,你可能会理解:
String className = “A”;Class c = Class.forName(className);factory = (AInterface)c.newInstance();
进一步,如果下面写,你可能会理解:
String className = readfromXMlConfig;//从xml 配置文件中获得字符串Class c = Class.forName(className);factory = (AInterface)c.newInstance();
上面代码就消灭了A类名称,优点:无论A类怎么变化,上述代码不变,甚至可以更换A的兄弟类B , C , D….等,只要他们继承Ainterface就可以。
从jvm的角度看,我们使用new的时候,这个要new的类可以没有加载;
但是使用newInstance时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是class的静态方法forName()方法,这个静态方法调用了启动类加载器(就是加载javaAPI的那个加载器)。
有了上面jvm上的理解,那么我们可以这样说,newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。
这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了我们降耦的手段。

[补充:]
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。(里面的一些名词搞不懂就算了,迟早都会学的,慢慢来)
里面就是通过这个类的默认构造函数构建了一个对象,如果没有默认构造函数就抛出InstantiationException, 如果没有访问默认构造函数的权限就抛出IllegalAccessException(问题产生原因:调用该类的构造方法,是Private访问权限)

2.理解Class.forName方法需要一些知识铺垫,也就是Class类的概念和类加载的概念

Class类概念

Class类用来描述一个类的结构,比如描述一个类有哪些成员,有哪些方法等。有多种方法可以获取一个类对应的Class类实例,比如:

 
//第一种方式获取描述Dog类结构的Class类实例
Class<Dog> clazz = Dog.class;
//第二种方式
Dog d = new Dog();
Class<Dog> clazz = d.getClass();

类加载概念

当使用一个类的时候(比如new一个类的实例),jvm会检查此类是否被加载到内存,如果没有,则会执行加载操作,加载操作的内容是,读取类对应的class文件数据,解析此数据,构造一个此类对应的Class类的实例,此Class类的实例描述了类的结构,并且提供了调用此类成员的接口。此时jvm就可以使用该类了,比如实例化此类,或者调用此类的静态方法。

java也提供了手动加载类的接口,class.forName()方法就是其中之一。

初始化参数指定的类,并且返回此类对应的Class实例。

类初始化概念

类被加载之后,jvm已经获得了一个描述类结构的Class实例。但是还需要进行类初始化操作之后才能正常使用此类,类初始化操作就是执行一遍类的静态语句,包括静态变量的声明还有静态代码块。

Class.forName方法

此方法含义是:加载参数指定的类,并且初始化它。

在jdbc连接数据库中的应用

到这里,不用解释,读者也会明白,在使用jdbc方式连接数据库时,为什么要执行Class.forName('驱动类名')方法了:将驱动类的class文件装载到内存中,并且形成一个描述此驱动类结构的Class类实例,并且初始化此驱动类,这样jvm就可以使用它了,这就是Class.forName()方法的含义。

猜你喜欢

转载自blog.csdn.net/hrw1234567890/article/details/81231788