RTTI的初期想法非常简单:当有一个指向基础型别base type的reference时,RTTI机制让你的一找出其所指的确切型别,不过当拓展到java.lang.reflection的时候,展现了全新的功能.即现在的java中存在两种形式的rtti:传统的rtti;reflection机制
为什么要使用rtti?上面的目的就是原因,比如向下转型downcasting/强制转型.
Class类对象以及他的装载时机。
如何取得某个类/对象的Class对象?
1.Class.forName("Gum");//可能导致执行期异常,比如说找不到Gum类,可以用于编译时还未形成的类
2.Gum.class;//这种方式要求编译时就装载Gum类,所以可以执行编译检查,一般不会出现找不到Gum类的情况,而且因为不是函数,性能得到优化.
我们明确知道Circle也是一个Shape,所以编译器能够自动上溯造型,但却不能保证一个Shape肯定是一个Circle.因此,编译器不允许自动下溯造型,除非明确指定一次这样的造型.
转型之前最好执行类型检查:(避免执行期异常ClassCastException)
1.传统转型:.instanceof if(x instanceof Dog) //这种运算符是使用老式关键字,他要求x必须为ref,所以不能用基本类型变量名,而后面的Dog也必须是Class,所以还是不能用基本类型.同时有个缺点就是Dog本身必须是Class名,根本不能用某种变量替换,相比于下面的方法缺少灵活性.
2.操作Class对象:Class.isInstance(obj)//比如Class c=Dog.class;if(c.isInstance(x))....obj也要求是object,输入基本类型系统会用基本类别wrap之,然后再判断,注意用基本类型来判断如int.class.isInstance(x)肯定会返回false,实在想不出你为啥要判断一个变量是否为基本类型...
Java运用Class对象来执行其RTTI机制——即使你所作的只是转型动作。
Class类型里面的几个有用的函数
getInterfaces() :Class[] //返回一系列接口的class对象。
newInstance() :Object //虚拟构造函数:我不知道你具体是什么东西,不过你给我适当的生成一个.若从表面看,Class的newInstance()方法似乎是克隆(clone())一个对象的另一种手段。但两者是有区别的。利用newInstance(),我们可在没有现成对象供“克隆”的情况下新建一个对象。就象上面的程序演示的那样,当时没有Toy对象,只有cy——即y的Class对象的一个句柄。利用它可以实现“虚拟构建器”。换言之,我们表达:“尽管我不知道你的准确类型是什么,但请你无论如何都正确地创建自己。”
static Class.forName("Gum"):Class
isInterface():bool //判断某个Class对象是否为interface.
getName():string //得到Class对象所属的类型的名字。
getSuperclass()
总之,有了某个类的Class对象,他的祖宗十八代都可以查出来。
事实上。RTTI和多态上有重复的功能,先尝试使用多态,最后才使用RTTI,记住,不要滥用RTTI.
Reflection机制也是通过Class类对象来实现的.
个人感觉他只不过是通过Class类对象暴露了一组共用的借口.我们可以查询并调用之,而并不用知道某个特定类的全部信息.事实上他并没有什么特别的神奇之处,总感觉有点似曾相识,有点像COM中提供的IUNKNOWN接口,或者IDL语言的作用?
采用传统RTTI:编译器在编译器即开启并检查.class文件,但如果采用Reflection机制,编译器并不会取用.class文件.它会由执行期环境加以开启和检查.由此我们可以看出reflection的使用场合:JavaBeans,RMI,object serialization.或者无法得知某.class文件提供的接口时.基本上我们编成的过程中不会直接用到Reflection.
即reflection的意思是我们用Class.forName()查找的class信息编译期间完全不可得,但是在运行的时候可以得到,我们一样可以查他的祖宗十八代。可以在运行时做任何编译是想做的事,比如我可以Class.forName()载入执行期才可见的某class,然后可以用class.newInstance(Constructor)来调用该类的某个构造函数构造一个对象,然后用method.invoke(args)来调用这个对象的某个方法。注意reflection机制拓展了Class类来支持更强的非基本rtti功能。
传统RTTI和“反射”之间唯一的区别就是对RTTI来说,编译器会在编译期打开和检查.class文件。换句话说,我们可以用“普通”方式调用一个对象的所有方法;但对“反射”来说,.class文件在编译期间是不可使用的,而是由运行期环境打开和检查。
想象一下javabean的实现吧,但是RMI,object serialization里如何应用reflection倒是需要仔细研究。
查一下java.lang.reflection包,发现包含以下内容:
接口 Member
类 Array
Constructor
Field
Method
Modifier
异常 InvocationTargetException