反射:能够分析类能力的程序称为反射,印象中sun公司在最初的两个版本就已经在jdk中发布了有关反向的声明,反射的功能及其强大,那它能做些什么呢?
- 在运行时分析类的能力
- 在运行时查看对象
- 实现通用的数组操作代码
- 利用Method对象,这个对象很想C++中的指针
看起来貌似很难理解,实际上呢,就是不好理解,索性就慢慢渗透吧。。。
反射是一种功能及其强大且复杂的机制,使用它的主要人员是工具的构造者,这里注意是构造者,一般我们都是使用一个工具,很少去向这些工具的生成原理,嘿,这里不就遇到了吗,就是利用复杂的反射,当然还有别的复杂机制,好了,不多说了,先看一下下面的基础知识。。
无论是百度百科,开始查看各种专业资料,学习Java反射最先接触的很定是Class对象,什么是Class对象呢?引用《Java核心技术》中的讲解:
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,这个信息跟踪者每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。然而,可以通过专门的Java类访问这些信息,保存这些信息的类被称为Class。
下面是Class类定义的源码,核心代码是看不到的:
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
private static final int ANNOTATION= 0x00002000;
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
private static native void registerNatives();
static {
registerNatives();
}
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
......
}
这个类中定义了很多的方法,就不多说了,感兴趣可以自己翻一下源码。。当然有一些方法我们之后还会用得到。就比如说我们获取Class类对象就用到的forName()方法。。。
我们接下来看一下获取Class类对象的实现:
比如一个Person对象表示一个特定的人员属性一样,一个Class对象将表示一个特定类的属性,最常用的Class方法是getName()。该方法可以获取指定类的类名,如果这个类在一个包里,包的名字也会作为类名的一部分。除了这种方法,我们还可以用上面说到的forName()方法,这是个静态方法,我们可以看一下Class类中定义该方法的源码:
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
caller = Reflection.getCallerClass();
if (sun.misc.VM.isSystemDomainLoader(loader)) {
ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(name, initialize, loader, caller);
}
/** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
如果类名保存在字符串中,并且可以在运行中改变,比较适合使用这个静态方法。当然,这个方法之后再className(代码看下面)是类名或者接口名的时候才可以执行。否则,forName方法将抛出一个checked exception 异常。注意:无论何时在使用这个方法,都应该提供一个异常处理器。
package reflection;
import java.util.Random;
/*
* 反射 获取Class类对象的三种方式
* 1、根据对象实例 调用 o.getClass().getName()方法
* 2、调用静态的forName()方法
* 3、根据Java类型也可以获取Class类对象
*/
public class Test1 {
public static void main(String[] args) {
Person p = new Person();
p.setAge(20);
p.setName("China");
System.out.println(p.getClass().getName() + " " + p.getName());
Random generator = new Random();
Class cl = generator.getClass();
String name = cl.getName();
System.out.println("name : " + name);
String className = "java.util.Random";
try {
Class cl2 = Class.forName(className);
System.out.println(cl2.getName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class cl3 = int.class;
System.out.println(cl3);
}
}
如果T是任意的Java类型,T.class将代表匹配的类对象。上面的代码中也有体现。
一个Class对象实际上指的是一个类型,而这个类型未必是一种类,就比如int.class不是类,但是int.class是一个Class类型的对象。