什么是反射
我们平时在创建对象的时候,一般都是通过直接new来获取,可以理解为这是正向的。反射我们可以理解为是反向的获取实例对象,他可以获取一个类的属性、构造器、方法、以及实现的接口等。
Class类
了解反射之前,我们最好先了解一个类:Class。这是一个什么样的类呢,有什么特殊的地方?我们平时自己编写的类,会定义一些属性、方法什么的,那系统存不存在一个类用来描述我们自己编写的类呢?我们自己写的类通过这个Class,就相当于自己照镜子一样,有哪些属性、那些方法、构造器等都会以Class的某种属性存在,Class就当是这样的一个类。任何一个类系统都会创建唯一的一个且仅有一个Class实例,一般我们获取某个实例的Class实例有三种方式,示例如下(假设我们有个Fruit类):
//方法一:通过类名直接获取
Class fruit = Fruit.class;
//方法二:先创建实例,通过实例的getClass方法获取
Fruit fruit1 = new Fruit();
Class fruitClass = fruit1.getClass();
//方法三:通过类的全路径获取
Class fruitClazz = null;
try {
fruitClazz = Class.forName("com.fanxing.Fruit");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
怎么证明他们的唯一性呢?
System.out.println(fruit == fruitClass); //true
System.out.println(fruit == fruitClazz); //true
System.out.println(fruitClazz == fruitClass); //true
Class知识点扩展:
在java中,任何class需要装在到JJVM才能运行:
-
forName()是装载类使用的,也就是将class类加载到JVM(new是根据加载到内存中的类创建实例,这是两者的区别)
-
什么时候使用forName呢?假设拥有一个类的全路径,如:com.example.Test,如何获取Test的实例呢?
-
Test test = (Test) Class.forName(“com.example.Test”).newInstance();
-
Test test = new Test();
以上两者的作用一样,都是创建一个Test实例
-
-
一个类在被装载到JVM的时候静态代码块会被执行,也就是在运行Class.forName(“com.example.Test”)的时候,Test类里面的static静态代码块会会执行,,且之后不会在重复执行,静态代码块和class是绑定关系。
-
Class.forName(XXX)的作用是告诉JVM查找XXX类并加载XXX,同时执行XXX里面的静态代码块。
在初始化一个类后,创建一个实例,使用newInstance()和new创建,除了一个是方法,一个是关键字之外,还有其他主要的区别吗?
-
它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。
-
从JVM的角度看,在使用new的时候不要求类已经被加载,但是使用newInStance()的时候必须要求亮点
- 类已经被加载
- 类已经连接了
而以上两个步骤就是Class.forName()完成的,这个静态方法调用了启动类加载器,也就是加载Java api的那个加载器。从上面可以看出,newInstance()实际上是将new的过程分解为两步,即首先调用Class的方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段
最后用最简单的描述来区分new关键字和newInstance()方法的区别
- newInstance: 弱类型。低效率。只能调用无参构造。
- new: 强类型。相对高效。能调用任何public构造。
Class类的一些常用方法
获取到了class对象,怎么获取到想要的属性或者方法或者构造器呢?下面我们对Class类的一些常用的方法做简单的介绍:
-
getName():
一个Class对象描述了一个特定类的属性,Class类中最常用的方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
-
newInstance():
Class还有一个有用的方法可以为类创建一个实例,这个方法叫做newInstance()。例如:
x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。 -
getClassLoader():
返回该类的类加载器
-
getSuperClass():
返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
-
isArray():
判定此 Class 对象是否表示一个数组类。
-
GetInterfaces():
获取当前class实现的接口(继承的不算)
-
getFields():
获取当前类的属性
-
getMethods():
获取当前类的方法
-
getConstructors():
获取当前类的构造方法
-
getField(String name):
获取指定名称的属性
-
getMethod(String name,Class<?> … parameterType):
获取指定名称的方法,并可传入参数
-
getConstructor(Class<?> … parameterType):
获取指定构造器,可传入参数