第14章 类型信息
14.2 Class对象
Class类:java.lang.Class 一个继承自java.lang.Object的模板类,RTTI的核心。每一个类都有一个Class类的对象,比如一个Teacher类,相应的就有一个Teacher的Class对象(程序启动前保存在Teacher.class文件中)。
所有的类都是在对其第一次使用时,动态加载到JVM中的。Java程序在它开始运行前并非被完全加载,其各个部分是在必须时才加载的。
比如对于一个Teacher类,类加载器首先检查Tearcher的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件(Tearcher.class)。一但Tearcher的Class对象被载入内存,他就被用来创建这个类的所有对象。
有两个方法可以获得某一个类的Class对象:
- Class.forName()
- Object.getClass()
- 类字面常量。这种形式与前两者有所不同,在于并不会初始化该Class对象。初始化被延迟到了对静态方法或者非常数静态域的首次引用时。
1 import static java.lang.System.out; 2 class Teacher { 3 Teacher(String name){this.name = name;} 4 public String getName(){return name;} 5 private String name = ""; 6 } 7 8 public class Test { 9 public static void main(String args[]){ 10 try { 11 Class teacherClass = Class.forName("Teacher"); 12 out.println(teacherClass); 13 out.println(teacherClass.getCanonicalName()); 14 out.println(teacherClass.getConstructors()); 15 out.println(teacherClass.isAnnotation()); 16 out.println(teacherClass.getClassLoader()); 17 out.println(teacherClass.getDeclaredFields()[0]); 18 out.println(teacherClass.getDeclaredMethods()[0]); 19 20 Teacher t = new Teacher("Peter"); 21 out.println(t.getClass()); 22 23 Class teacherClass2 = Teacher.class; 24 out.println(teacherClass2); 25 } 26 catch (Exception e) { 27 e.printStackTrace(); 28 } 29 } 30 }/*Output: 31 class Teacher 32 Teacher 33 [Ljava.lang.reflect.Constructor;@14318bb 34 false 35 sun.misc.Launcher$AppClassLoader@addbf1 36 private java.lang.String Teacher.name 37 public java.lang.String Teacher.getName() 38 class Teacher 39 class Teacher 40 */
泛化的Class引用,下面这段代码初次读的时候没搞明白什么意思。
1 import java.util.*; 2 class CountedInteger{ 3 private static long counter; 4 private final long id = counter++; 5 public String toString() {return Long.toString(id);} 6 } 7 8 public class FilledList<T> { 9 private Class<T> type; 10 public FilledList(Class<T> type){this.type=type;} 11 public List<T> create(int nElements){ 12 List<T> l = new ArrayList<T>(); 13 try{ 14 for(int i = 0; i < nElements; ++i) 15 l.add(type.newInstance()); 16 } 17 catch(Exception e){ 18 throw new RuntimeException(e); 19 } 20 return l; 21 } 22 public static void main(String args[]){ 23 FilledList<CountedInteger> fl = new FilledList<CountedInteger>(CountedInteger.class); 24 System.out.println(fl.create(15)); 25 } 26 }/* 27 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] 28 */
注意:如果想要用Class.newIntance()方法的话,那么这个Class必须有一个默认构造器。
14.3 类型转换前先做检查
Java的三种RTTI形式:
1. 传统的类型转换,如(DeriveType)baseTypeObject;由RTTI确保了类型转换的正确性,如果执行一个错误的类型转换,就会抛出一个ClassCastException异常。
2. Class对象。(如前面介绍的)
3. instanceof
14.7 动态代理
http://www.techavalanche.com/2011/08/24/understanding-java-dynamic-proxy/
14.9 接口与类型信息
在反射面前,一切信息都无法隐藏。
java.lang.reflect.AccessibleObject接口定义了 setAccessible()方法可以修改访问权限。Constructor,Field和Method类都实现了这个接口。