反射机制的相关类【转载】

宋正兵 on 2020-12-09

转载地址:Java高级特性——反射

除了转载的内容外,加入了部分实验代码。

反射机制的相关类

与Java反射相关的类如下:

类名 用途
Class类 代表类的实体,在运行的 Java 应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法

Class类

它位于 java.lang 包中,其构造函数是私有的,由 JVM(类加载器)创建 Class 对象,我们可以通过 getClass() 方法获取到 Class 对象。

1
2
3
4
5
6
7
/*
* 私有构造函数,使得只有jvm可以创建该类的对象,这个私有构造函数还可以防止通过默认构造函数创建类对象
*/
private Class(ClassLoader loader) {
// 初始化final变量ClassLoader
classLoader = loader;
}

利用 Class 对象,我们可以拿到创建的类的属性、方法等。

Class 类的作用

  1. 获取类中属性的类型
  2. 获取类中属性的名称
  3. 获取类的方法
  4. 获取类的基类等等
  5. 利用 Class 类完成反射

Class 类的主要方法

获得类相关的方法

带有Declared修饰的方法可以反射到私有的方法,没有Declared修饰的只能用来反射公有的方法

方法 用途
asSubclass(Class clazz) 把传递的类的对象转换成代表其子类的对象
Cast 把对象转换成代表类或是接口的对象
getClassLoader() 获得类的加载器
getClasses() 返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses() 返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String className) 根据类名返回类的对象
getName() 获得类的完整路径名字
newInstance() 创建类的实例
getPackage() 获得类的包
getSimpleName() 获得类的名字
getSuperclass() 获得当前类继承的父类的名字
getInterfaces() 获得当前类实现的类或是接口

获得类中属性相关的方法

方法 用途
getField(String name) 获得某个公有的属性对象
getFields() 获得所有公有的属性对象
getDeclaredField(String name) 获得某个属性对象
getDeclaredFields() 获得所有属性对象

获得类中注解相关的方法

方法 用途
getAnnotation(Class annotationClass) 返回该类中与参数类型匹配的公有注解对象
getAnnotations() 返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass) 返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations() 返回该类所有的注解对象

获得类中构造器相关的方法

方法 用途
getConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法
getConstructors() 获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的构造方法
getDeclaredConstructors() 获得该类所有构造方法

获得类中方法相关的方法

方法 用途
getMethod(String name, Class…<?> parameterTypes) 获得该类某个公有的方法
getMethods() 获得该类所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes) 获得该类某个方法
getDeclaredMethods() 获得该类所有方法

类中其他重要的方法

方法 用途
isAnnotation() 如果是注解类型则返回 true
isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果是指定类型注解类型则返回 true
isAnonymousClass() 如果是匿名类则返回 true
isArray() 如果是一个数组类则返回 true
isEnum() 如果是枚举类则返回 true
isInstance(Object obj) 如果 obj 是该类的实例则返回 true
isInterface() 如果是接口类则返回 true
isLocalClass() 如果是局部类则返回 true
isMemberClass() 如果是内部类则返回 true

forName 方法

  • 加载类: public static Class<?> forName(String className) throws ClassNotFoundException

输入需要加载的类的全路径名,得到类的 Class 对象。

1
2
3
4
5
6
7
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("cn.my.vo.Person");
System.out.println(cls.getName());// 获取类的完整名称
}
}
// Person类放在cn.my.vo开发包中

newInstance 方法

代替关键字 new,提供了对象的反射实例化方法。

在 JDK 1.9 之前的实例化:public T newInstance() throws InstantiationException, IllegalAccessException

范例:通过newInstance()方法实例化Person对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* package cn.my.vo中Person.java */
public class Person {
// 任何情况下如果要实例化对象则一定要调用类中的构造方法
public Person() {
System.out.println("*****Person类构造方法*****");
}
@Override
public String toString() {
return "一个Person类";
}
}
/* JavaAPIDemo.java */
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("cn.my.vo.Person");
Object obj = cls.newInstance();// 实例化对象,JDK 1.9后被废除了
System.out.println(obj); // 输出对象调用toString()方法
}
}
/* output
【cls.newInstance()、关键字new】*****Person类构造方法*****
【System.out.println(obj)】一个Person类
*/

在 JDK 1.9 之后:clazz.getDeclaredConstructor().newInstance()

范例:替代newInstance()方法实例化Person对象

1
2
3
4
5
6
7
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("cn.my.vo.Person");
Object obj = cls.getDeclaredConstructor().newInstance();
System.out.println(obj); // 输出对象调用toString()方法
}
}

isInstance 方法

isInstance() 方法与操作符 instanceof 功能是等价的。用于检查指定的对象是否兼容分配给该 Class 的实例。如果指定对象为非 null,并且可以强制转换为此类的实例,则该方法返回 true,否则返回 false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TestInfo {

static {
System.out.println("我是谁");
}

public TestInfo(){
System.out.println("我是构造函数");
}
public String test="测试属性";
public static void main(String[] args) {
TestClass info=new TestClass();
//返回结果是true因为info是子类的对象
System.out.println(TestInfo.class.isInstance(info));
}

}
class TestClass extends TestInfo{}

getName、getTypeName、getCanonicalName、getSimpleName 方法 参考

public String getName() 返回表示的类或接口的名称,例如String.class.getName() 将会返回 "java.lang.String" 。可以理解为返回的是虚拟机中 Class 对象的表示。同时会根据不同的类型,链接不同的符号加以表示。

public String getTypeName() 返回此类型名称的信息字符串。可以理解为返回该类类型的名称。

public String getCanonicalName() 返回基础类的规范名称(如果存在),否则为null。可以理解为返回的是正常的包含路径的类名。

public String getSimpleName() 返回源代码中给出的基础类的简单名称,如果基础类是匿名的,则返回空字符串。可以理解为返回的仅仅是类名,不包含路径。

提供下面的例子,以便直观地感受四个方法之间的差异。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class AAA {

class BBB {
}

public static void main(String[] args) {
// 数组
System.out.println(String[].class.getName()); // [Ljava.lang.String;
System.out.println(String[].class.getCanonicalName()); // java.lang.String[]
System.out.println(String[].class.getSimpleName()); // String[]
System.out.println(String[].class.getTypeName()); // java.lang.String[]

// 成员内部类
System.out.println(BBB.class.getName()); // lang.reflect.AAA$BBB
System.out.println(BBB.class.getCanonicalName()); // lang.reflect.AAA.BBB
System.out.println(BBB.class.getSimpleName()); // BBB
System.out.println(BBB.class.getTypeName()); // lang.reflect.AAA$BBB

// 匿名内部类
System.out.println(new Object(){}.getClass().getName()); // lang.reflect.AAA$1
System.out.println(new Object(){}.getClass().getCanonicalName()); // null
System.out.println(new Object(){}.getClass().getSimpleName()); // ""
System.out.println(new Object(){}.getClass().getTypeName()); // lang.reflect.AAA$4

// 普通类
System.out.println(AAA.class.getName()); // lang.reflect.AAA
System.out.println(AAA.class.getCanonicalName()); // lang.reflect.AAA
System.out.println(AAA.class.getSimpleName()); // AAA
System.out.println(AAA.class.getTypeName()); // lang.reflect.AAA

// 基本数据类型
System.out.println(int.class.getName()); // int
System.out.println(int.class.getCanonicalName()); // int
System.out.println(int.class.getSimpleName()); // int
System.out.println(int.class.getTypeName()); // int
}
}

Field类

Field代表类的成员变量(成员变量也称为类的属性)。

方法 用途
equals(Object obj) 属性与 obj 相等则返回 true
get(Object obj) 获得 obj 中对应的属性值
set(Object obj, Object value) 设置 obj 中对应属性值

Method类

Method代表类的方法。

方法 用途
invoke(Object obj, Object… args) 传递 object 对象及参数调用该对象对应的方法

Constructor类

Constructor代表类的构造方法。

方法 用途
newInstance(Object… initargs) 根据传递的参数创建类的对象