1.我们需要类型信息有什么用?
- 类型转换时检查是否可行,在java中所有的类型转换都是在运行时进行正确性检查的。这里就必须用到类型信息。
- 在继承体系中有时候需要知道基类对象引用所指向的对象的具体类型,以做一些具体的操作。
2.类型信息在运行时是如何表示的?
- Class对象,它包含了与类有关的信息。类型检查实际上用到了这个对象(说法来自java编程思想)
- 每当编写并编译了一个新类就会产生一个Class对象。这被保存在同名的.class文件中。
- 获得Class对象引用的方法有两个:Class.forName()方法;类字面常量Toy.class;两者的区别是后者在编译时就会受到检查,更加高效。后面还会具体介绍到。
3.已知的RTTI形式(来自编程思想)
- 传统的类型转换(实际上用到了第二种)
- 代表对象类型的Class对象。
- 关键字instanceof
4.一些方法
- Class.forName("typeinfo.Pet")方法:用途1 获得参数所指示的Class对象的引用;用途2 加载尚未加载的类。一般置于trycatch块中,因为编译时不知道能不能找到目标类
- Class对象引用所具有的方法 Class c= Pet.class; c.getName(); c.getSimpleName();c.getCanonicalName();c.isInterface();c.getInterfaces();c.getSuperClass();
- 接上例。c.newInstance()方法。返回的类型是Object。弱类型,反射时用,待创建的类必须有默认的构造器。
5.泛化的Class引用
- 在这里使用泛型语法的目的:让编译器强制执行编译器类型检查。
- Class<?>非具体的Class对象引用,主要用途 Class<? extends Number>。虽然Integer继承自Number,但是Integer的Class对象并不是Number的Class对象的引用。
6.使用类之前所做的准备(三步)
- 加载,由类加载器执行。具体则是查找字节码,并创建一个Class对象。
- 链接。验证字节码,为静态域分配存储空间(并未初始化),有必要的话,解析这个类创建的对其他类的引用。
- 初始化。先超类。执行静态初始化器(?)和静态初始化块。
- 初始化被延迟到了对静态方法(包含构造器)或者非final静态域首次引用时才执行。
- static final值是"编译器常量",不需要类初始化就可以访问。(它的初始化在链接之前就玩成了。)
7.instanceof和isInstance()以及isAssignableFrom()
- if(x instanceof Dog) ((Dog)x).bark();
对于instanceof有比较严格的限制:
关键字右边只能是类型名称(Dog)而不是Class对象引用。(局限太大了)
- MyType.class.isInstance(obj);//判断obj对象是否是MyType类型的实例,obj必须是对象
这是一个naitive方法,jdk1.1引入
-
basetype .isAssignableFrom(type)//两边都是Class对象引用,完全动态
8.在查询类型信息时,使用instanceof和直接用==/equals()方法比较有重要差别。
==/equals()方法比较的是实际的Class对象,并没有考虑继承。
9.反射 import java.lang.reflect.*;
- 并不是所有的Class对象都能在编译时明确,某些情况下需要在运行时再发现和确定类型信息
- 比如:JavaBeans提供了基于构件的编程框架,另一个例子是远程方法调用
- java.lang.reflect类库中包含了Field、Method以及Constructor类(每个类都实现了Member接口)。这些类型的对象是由虚拟机在运行时创建的,用以表示未知类里对应的成员。
- Class类中的getField()、getMethod()、getConstructor()方法返回表示字段/方法以及构造器对象的数组
- get和set方法读取和修改与Field对象关联的字段
- invoke()方法调用与Method对象关联的方法。
- 通过以上方法足以将匿名对象的类信息在运行时完全确定下来。
- ----------------------------------------------------------
- JVM在遇到未知类型的对象时,会检查看它属于哪个特定的类,也就是说.class文件对于JVM来说是必不可少的。
- RTTI和反射之间真正的区别是RTTI在本地编译时打开和检查.class文件
- 而对于反射机制来说,.class文件在编译时是不可获取的,所以在运行时打开和检查.class文件
- ----------------------------------------------------------
- 反射在java中是用来支持对象序列化和JavaBean的。(还没有学到,暂时不了解)
10.动态代理暂时不想看
11.接口与类型信息
static
void
callHiddenMethod(Object a, String methodname)
throws
Exception {
Method g = a.getClass().getDeclaredMethod(methodname);
g.setAccessible(
true
);
g.invoke(a);
}
不论是包访问权限/内部类/匿名内部类都不能阻止反射,只有final域可以。