上海网站备案需要多久,CQ网络科技网站建设,公司网站自己可以做吗,浅析淘宝网站的建设与运营论文转载自 「深入Java」类型信息#xff1a;RTTI和反射 1.RTTI Run-Time Type Infomation 运行时类型信息 为什么需要RTTI#xff1f; 越是优秀的面向对象设计#xff0c;越是强调高内聚低耦合#xff0c;正如依赖倒转原则所说#xff1a;“无论是高层模块还是低层模块#…转载自 「深入Java」类型信息RTTI和反射 1.RTTI Run-Time Type Infomation 运行时类型信息 为什么需要RTTI 越是优秀的面向对象设计越是强调高内聚低耦合正如依赖倒转原则所说“无论是高层模块还是低层模块都应该针对抽象编程”。 比如说我们有一个抽象父类
Shape draw() 以下是三个具体类
Circle draw()
Square draw()
Triangle draw() 某些情况下我们持有Shape但却远远不够——因为我们想要针对它的具体类型进行特殊处理然而我们的设计完全针对抽象所以在当前上下文环境中无法判断具体类型。 因为RTTI的存在使得我们在不破坏设计的前提下得以达到目的。 Class类与Class对象 事实上每一个类都持有其对应的Class类的对象的引用Object类中的getClass()能让我们获取到它其中包含着与类相关的信息。 非常容易注意到针对每一个类编译Java文件会生成一个二进制.class文件这其中就保存着该类对应的Class对象的信息。 .class是用于供类加载器使用的文件 Java程序在运行之前并没有被完全加载各个部分是在需要时才被加载的。 为了使用类而作的准备包含三步
加载。由类加载器执行查找字节码创建一个Class对象。链接。验证字节码为静态域分配存储空间如果必需的话会解析这个类创建的对其他类的所有引用比如说该类持有static域。初始化。如果该类有超类则对其初始化执行静态初始化器[注]和静态初始化块。 注原文为static initializers经查看Thinking in Java其意应为静态域在定义处的初始化如 static Dog d new Dog(0);。 所有的类都是在对其第一次使用时动态加载到JVM中去的。当程序创建第一个对类的静态成员的引用时JVM会使用类加载器来根据类名查找同名的.class——一旦某个类的Class对象被载入内存它就被用来创建这个类的所有对象。构造器也是类的静态方法使用new操作符创建新对象会被当作对类的静态成员的引用。 注意特例如果一个static final值是编译期常量读取这个值不需要对类进行初始化。所以说对于不变常量我们总是应该使用static final修饰。 Class.forName(String str) Class类有一个很有用的静态方法forName(String str)可以让我们对于某个类不进行创建就得到它的Class对象的引用例如这个样子
try {Class toyClass Class.forName(com.duanze.Toy); // 注意必须使用全限定名
} catch (ClassNotFoundException e) {} 然而使用forName(String str)有一个副作用如果Toy类没有被加载调用它会触发Toy类的static子句静态初始化块。 与之相比更好用的是类字面常量像是这样:
Class toyClass Toy.class; 支持编译时检查所以不会抛出异常。使用类字面常量创建Class对象的引用与forName(String str)不同不会触发Toy类的static子句静态初始化块。所以更简单更安全更高效。 类字面常量支持类、接口、数组、基本数据类型。 ×拓展× Class.forNameString className使用装载当前类的类装载器来装载指定类。因为class.forName(String className)方法内部调用了Class.forName(className, true, this.getClass().getClassLoader())方法如你所见第三个参数就是指定类装载器显而易见它指定的是装载当前类的类装载器的实例也就是this.getClass().getClassLoader(); 你可以选择手动指定装载器
ClassLoader cl new ClassLoader();
Class c1 cl.loadClass(String className, boolean resolve ); 更详细的参考 范化的Class引用 通过范型以及通配符我们能对Class对象的引用进行类型限定像是
ClassInteger intClass int.class; // 注意右边是基本数据类型的类字面常量 这样做的好处是能让编译器进行额外的类型检查。 知道了这一点以后我们可以把之前的例子改写一下
Class toyClass Toy.class;
Class? toyClass Toy.class; 虽然这两句是等价的但从可读性来说Class?要优于Class这说明编程者并不是由于疏忽而选择了非具体版本而是特意选择了非具体版本。 Class.newInstance() 既然拿到了包含着类信息的Class对象的引用我们理应可以构造出一个类的实例。Class.newInstance()就是这样一个方法比如
// One
try {Class? toyClass Class.forName(com.duanze.Toy); Object obj toyClass.newInstance();
} catch (ClassNotFoundException e) {}// Two
Class? toyClass Toy.class;
Object obj toyClass.newInstance(); 使用newInstance()创建的类必须带有默认构造器。 由于toyClass仅仅只是一个Class对象引用在编译期不具备更进一步的类型信息所以你使用newInstance()时只会得到一个Object引用。如果你需要拿到确切类型需要这样做
ClassToy toyClass Toy.class;
Toy obj toyClass.newInstance(); 但是如果你遇到下面的情况还是只能拿到Object引用
ClassSubToy subToyClass SubToy.class;
Class? super SubToy upClass subToy.getSuperclass(); // 希望拿到SubToy的父类Toy的Class对象引用
// This wont compile:
// ClassToy upClass subToy.getSuperclass();
// Only produces Object:
Object obj upClass.newInstance(); 虽然从常理上来讲编译器应该在编译期就能知道SubToy的超类是Toy但实际上却并不支持这样写
// This wont compile:
ClassToy upClass subToy.getSuperclass(); 而只能够接受
Class? super SubToy upClass subToy.getSuperclass(); // 希望拿到SubToy的父类Toy 这看上去有些奇怪但现状就是如此我们惟有接受。好在这并不是什么大问题因为转型操作并不困难。 类型检查 在进行类型转换之前可以使用instanceof关键字进行类型检查像是
if ( x instanceof Shape ) {Shape s (Shape)x;
} 一般情况下instanceof已经够用但有些时候你可能需要更动态的测试途径:Class.isInstance(Class clz):
ClassShape s Shape.class;
s.isInstance(x); 可以看到与instanceof相比isInstance()的左右两边都是可变的这一动态性有时可以让大量包裹在if else...中的instanceof缩减为一句。 2.反射 不知道你注意到了没有以上使用的RTTI都具有一个共同的限制在编译时编译器必须知道所有要通过RTTI来处理的类。 但有的时候你获取了一个对象引用然而其对应的类并不在你的程序空间中怎么办这种情况并不少见比如说你从磁盘文件或者网络中获取了一串字串并且被告知这一串字串代表了一个类这个类在编译器为你的程序生成代码之后才会出现。 Class类和java.lang.reflect类库一同对反射的概念提供了支持。反射机制并没有什么神奇之处当通过反射与一个未知类型的对象打交道时JVM只是简单地检查这个对象看它属于哪个特定的类。因此那个类的.class对于JVM来说必须是可获取的要么在本地机器上要么从网络获取。所以对于RTTI和反射之间的真正区别只在于
RTTI编译器在编译时打开和检查.class文件反射运行时打开和检查.class文件 明白了以上概念后什么getFields(),getMethods(),getConstructors()之类的方法基本上全都可以望文生义了。 我们可以看一下Android开发中经常用的对于ActionBar让Overflow中的选项显示图标这一效果是怎么做出来的
/*
overflow中的Action按钮应不应该显示图标
是由MenuBuilder这个类的setOptionalIconsVisible方法来决定的
如果我们在overflow被展开的时候给这个方法传入true
那么里面的每一个Action按钮对应的图标就都会显示出来了。
*/Override
public boolean onMenuOpened(int featureId, Menu menu) {if (featureId Window.FEATURE_ACTION_BAR menu ! null) {if (menu.getClass().getSimpleName().equals(MenuBuilder)) {try {// Boolean.TYPE 同 boolean.classMethod m menu.getClass().getDeclaredMethod(setOptionalIconsVisible, Boolean.TYPE); // 通过setAccessible(true)确保可以调用方法——即使是private方法m.setAccessible(true);// 相当于menu.setOptionalIconsVisible(true) m.invoke(menu, true);} catch (Exception e) {}}}return super.onMenuOpened(featureId, menu);
} ×拓展动态代理× Java中对于反射的一处重要使用为动态代理可以参考这篇IBM developerworks的文章 参考资料
《Java编程思想》http://blog.csdn.net/guolin_blog/article/details/18234477#t7http://yanwushu.sinaapp.com/class_forname/