反射之.getClass、.class、Class.forName的区别

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

传统的编程方法要求程序员在编译阶段决定使用的类型,但是在反射的帮助下,编程人员可以动态获取这些信息,从而编写更加具有可移植性的代码。

获得Class对象

.getClass、.class、Class.forName是三种获得Class对象的方法。因为一切皆为对象,所以类型也不例外。

  • getClass()接在对象的后面。getClass()是Object类中的方法,而Object类是所有Java类的父类。
  • .class接在任意一个Java类型的后面,在编译期加载(静态加载)。
  • Class.forName是Class类中的一个静态方法,从指定的classloader中装载类,返回与给定字符串对应类或接口的Class对象,在运行期加载(动态加载)。

关于静态加载和动态加载:

  1. 静态加载的类的源程序在编译时期加载(必须存在),而动态加载的类在编译时期可以缺席(源程序不存在时编译器也不会报错)。
  2. 当类找不到的时候,静态加载方式会抛出异常”NoClassDefFoundError”,而动态加载方式则抛出”ClassNotFoundException”异常。

这三种方法获得的Class对象都是一模一样的,我们可以写一段简短的代码来验证一下。

1
2
3
4
5
6
7
8
9
10
11
12
public class CompareObject {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class c1 = new Robot().getClass(); //使用.getClass()创建Class对象
Class c2 = Robot.class; // 使用.class创建Class对象
Class c3 = Class.forName("com.shenghai.javabasic.reflect.Robot"); //使用反射创建Class对象

if (c1 == c2 && c1 == c3 && c2 == c3)
System.out.println("three classes are equal");
}
}

// 输出为 three classes are equal

从Class对象中获取该类的各种信息

在得到Class对象之后,我们可以调用以下这些方法来获取该类的各种信息,包括类名、父类以及它所实现接口的名字等。

1
2
3
4
5
6
7
8
public static void printClassInfo(Class c) {
System.out.println(c.getName()); //获得该Class对象的全称名称
System.out.println(c.getSuperclass()); //getSuperclass()获得该Class对象的直接父类
System.out.println(c.getInterfaces()); //getInterfaces()获得该Class对象实现的所有接口
System.out.println(c.isArray()); //isArray()判断该Class对象是否为数组类
System.out.println(c.getMethods()); //getMethods()取得该Class对象所有共有方法
System.out.println(c.getClassLoader()); //getClassLoader()取得该Class对象的类装载器
}