反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。
反射是为了解决在运行期,对某个实例一无所知的情况下,如何调用其方法
除了int
等基本类型外,Java的其他类型全部都是class
(包括interface
)。例如:
String
Object
Runnable
Exception
可以得出结论:class
(包括interface
)的本质是数据类型(Type
)。无继承关系的数据类型无法赋值:
Number n = new Double(123.456); // OK String s = new Double(123.456); // compile error!
而class
是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class
类型时,将其加载进内存。
每加载一种class
,JVM就为其创建一个Class
类型的实例,并关联起来。注意:这里的Class
类型是一个名叫Class
的class
。它长这样:
public final class Class { private Class() {} }
以String
类为例,当JVM加载String
类时,它首先读取String.class
文件到内存,然后,为String
类创建一个Class
实例并关联起来:
Class cls = new Class(String);
这个Class
实例是JVM内部创建的,如果我们查看JDK源码,可以发现Class
类的构造方法是private
,只有JVM能创建Class
实例,我们自己的Java程序是无法创建Class
实例的。
所以,JVM持有的每个Class
实例都指向一个数据类型(class
或interface
):
┌───────────────────────────┐ │ Class Instance │──────> String ├───────────────────────────┤ │name = "java.lang.String" │ └───────────────────────────┘ ┌───────────────────────────┐ │ Class Instance │──────> Random ├───────────────────────────┤ │name = "java.util.Random" │ └───────────────────────────┘ ┌───────────────────────────┐ │ Class Instance │──────> Runnable ├───────────────────────────┤ │name = "java.lang.Runnable"│ └───────────────────────────┘
一个Class
实例包含了该class
的所有完整信息:
┌───────────────────────────┐ │ Class Instance │──────> String ├───────────────────────────┤ │name = "java.lang.String" │ ├───────────────────────────┤ │package = "java.lang" │ ├───────────────────────────┤ │super = "java.lang.Object" │ ├───────────────────────────┤ │interface = CharSequence...│ ├───────────────────────────┤ │field = value[],hash,... │ ├───────────────────────────┤ │method = indexOf()... │ └───────────────────────────┘
由于JVM为每个加载的class
创建了对应的Class
实例,并在实例中保存了该class
的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class
实例,我们就可以通过这个Class
实例获取到该实例对应的class
的所有信息。
这种通过Class
实例获取class
信息的方法称为反射(Reflection)。
方法一:直接通过一个class
的静态变量class
获取:
Class cls = String.class;
方法二:如果我们有一个实例变量,可以通过该实例变量提供的getClass()
方法获取:
String s = "Hello"; Class cls = s.getClass();
方法三:如果知道一个class
的完整类名,可以通过静态方法Class.forName()
获取:
Class cls = Class.forName("java.lang.String");
Class
实例比较和instanceof
的差别:
Integer n = new Integer(123); boolean b3 = n instanceof Integer; // true boolean b4 = n instanceof Number; // true boolean b1 = n.getClass() == Integer.class; // true boolean b2 = n.getClass() == Number.class; // false
用instanceof
不但匹配当前类型,还匹配当前类型的子类。而用==
判断class
实例可以精确地判断数据类型,但不能作子类型比较。
通常情况下,我们应该用instanceof
判断数据类型,因为面向抽象编程的时候,我们不关心具体的子类型。只有在需要精确判断一个类型是不是某个class
的时候,我们才使用==
判断class
实例