RTTI的一个例子:
Shape.png
Shape对象具体的draw逻辑是由引用所指向的具体对象Circle,Square或者Triangle决定的,这就是多态。
java在运行时识别类和对象的信息主要有两种方式:
- 传统的“RTTI”,在编译时已知道了所有的类型
- java 反射,在运行时发现和使用类的信息
Class
Java使用Class对象来执行器RTTI,Class对象是用来描述类信息的特殊对象,每个类都对应一个Class对象(被保存在同名的.class文件中)。可通过Class.forName(类的全限定名)或者类名.class获取Class对象的引用,通过引用创建类的示例。
所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用static关键字。因此,使用new操作符创建类的新对象也会被当做对类的静态成员的引用。因此,java程序在它开始运行之前并非完全加载,其各个部分是在必需时才加载的。
为了使用类而做的准备工作包含3个步骤:
- 加载 这是由JVM上的加载器执行的,该步骤将查找字节码并创建一个Class对象
- 链接 验证静态类中的字节码,为静态域分配存储空间。如果必须的话,解析这个类创建的对其它类的引用
- 初始化 如果该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化块。
java反射
RTTI与反射之间的区别仅在于,RTTI在编译时已知道类的所有信息,而对于反射机制来说,.class文件在编译时是不可获取的,而是在运行阶段发现或获取类的信息。
Class类与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了Fileld,Method以及Constructor类。这些类型的信息是有JVM在运行时创建的,用以表示未知类里的成员。这样就可以使用Constructor创建新的队形,用get()方法和set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。这样,匿名的对象就能在运行时被完全确定下来,而在编译时不需要知道任何事情。
动态代理
动态代理是一种在运行时构建动态代理、动态处理代理方法调用的机制,从而在运行时实现调用者和实现者的解耦。下面是JDK 动态代理的一个简单例子:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyDynamicProxy {
public static void main(String[] args) {
HelloImpl hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello);
Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
proxyHello.sayHello();
}
}
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello(){
System.out.println("Hello world");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Invoking sayHello");
Object result = method.invoke(target, args);
return result;
}
}
动态代理机制可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,如
上例的MyInvocationHandler。
网友评论