转载请注明出处:jiq?钦‘s
technical Blog
1 Class文件:
class文件全名称为Javaclass文件,主要在平台无关性和网络移动性方面使Java更适合网络。它在平台无关性方面的任务是:为Java程序提供独立于底层主机平台的二进制形式的服务。
每一个类都有一个Class类型的对象,每当一个类被编译,就会产生一个Class对象(保存在同名的.class文件中);
2 Class文件加载时机:
运行时按需加载。
与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM,然后再根据需要在运行时把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader。
三种情况会触发Class Loader动态加载class对象到JVM:
(1)第一次静态方法被调用;
(2)第一次被new实例化;
(3)包含静态代码块;
一旦某个类的Class对象被载入内存,他就被用来创建这个类所有对象;
3 RTTI三种表现形式:
Java是借助Class对象来实现RTTI机制的,java中RTTI有三种表现形式:
1).传统的类型转化。
如Base类是Subclass类基类。
Base base = newSubclass();
Subclass sub=(Subclass)base;//由RTTI确定类型转化正确性
2).通过代表对象的类型的Class对象可以获取运行时所需的信息。
3).关键字“instanceof”判断对象类型。
如:boolean yesOrNot = (baseinstanceof Subclass);
若base是Subclass类的实例,yesOrNot就为true。
4 RTTI限制:
书上流传一句话:RTTI和反射的区别是,对RTTI来说,编译器在编译时打开和检查.class文件,对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
这个要怎么理解呢???
RTTI是在编译期间就已经知道了所有要处理的类型,但是有时运行时需要解析一个对象,比如你在磁盘文件或者网络中获取了一串字节,并被告知这些字节代表某一个类,但是很不幸代码中没有任何相关操作触发对应的class文件被加载到JVM,这就是所谓的运行时打开和检查.class文件。
5
反射机制
这时就需要通过显式告知JVM加载哪个class文件,以获取对应类型信息。
取得Class对象(若还未加载则先加载)的引用有两种方式:
(1)方法Class.forName("className")
(2) .class 类字面常量。
两者区别在于后者会将类的初始化(static区域的执行)推迟到后面对该类的静态域引用的时候;
Class<?>classObject = Class.forName("className");
Method[]methods = classObject.getMethods();
Constructor[]ctors = classObject.getConstructors();
由此可见,Class类是RTTI的基础,而Class类与java.lang.reflect类库一起对反射概念进行了支持。
6
反射的不安全性
即使你是面向接口编程,只提供出“希望可见的部分”给客户端,但是你仍然无法避免你的不可见的私有的,或者不是私有的一切方法被客户端使用的命运,你无法阻止这样的耦合。客户端通过反编译+反射机制就可以突破你的任何防线。但是如果有人这么干了,那这是他们的责任。
7 Spring中的依赖注入
Spring中的依赖注入就是依靠反射机制才得以实现的。
首先Spring会读取器配置文件中配置的那些bean,然后获取其要注入的对象的类名,这样就可以根据:
Classs bean = Class.forName("className");
Objectoo = bean.newInstance();
这样就创建好了一个待注入的类的对象。
我们利用反射机制一样可以获取注入目标Action的所有方法,包括其setXXX方法,因此我们接下来便可以通过调用
Method#invoke(方法名称,参数)这个方法来将创建好的对象注入进去了。
8 利用反射机制创建实例:
(1) 创建普通实例:
(2) 创建一维数组:
(3) 创建二维数组: