java学习笔记---类型信息(type information)、反射机制与动态代理
2013-04-28 18:54
1091 查看
(1)Class对象
要理解RTTI在java 中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由成为Class对象的特殊对象完成的,它包含了与类有关的信息。
Class.forName(String classname):Class类的静态方法,参数字符串必须包含包名,返回Class对象。
运行结果:
java还提供了另一种方法来生成Class对象的引用,即使用类字面常量。类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型。另外对于基本数据类型的包装类,还有一个标准字段TYPE。TYPE字段是一个引用,指向对应的基本数据类型的Class对象,如下所示:
当使用“.class”来创建对Class对象的引用时,不会自动的初始化该Class对象。为了使用类而坐的准备工作实际包含三个步骤:
1)加载,这是由类加载器执行的。该步骤查找字节码,并从这些字节码中创建一个Class对象。
2)链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。
3)初始化。如果该类具有超累,则对其初始化,执行静态初始化器和静态初始化块。
如果一个static final值是“编译器常量”,那么这个值不需要对其所属类进行初始化就可以被读取。但是只是将一个域设置为static或者final的,还不足以确保这种行为。
Class引用所指向的Class对象可以进行限定,这里使用了Class的泛化语法。
当将泛型语法用于Class对象时,newInstance ()方法将返回该对象的确切类型,而不仅仅是在ToyTest.java中看到的基本的Object。
(2)类型转换前先做检查
某个对象是不是某个类的实例
静态检查:instanceof()
动态检查:isInstance()
(3)instanceof与Class的等价性
输出结果是:
instanceof()和isInstance()结果完全一样,equals()和==也一样。instanceof保持了类型的概念,它指的是“你是这个类吗?或者你是这个类的派生类吗?”而如果使用==比较实际的Class对象,就没有考虑继承----它或者是这个确切类型,或者不是。
(4)动态代理
代理是基本的设计模式之一,它是你为了提供的额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。下面是一个用来展示代理结构的简单示例:
输出结果是:
java的动态代理比代理的思想要向前迈进了一步,因为它可以动态创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器(InvocationHandler),他的工作是解释调用的类型并确定相应的对策。
输出结果是:
通过调用Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。
要理解RTTI在java 中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由成为Class对象的特殊对象完成的,它包含了与类有关的信息。
Class.forName(String classname):Class类的静态方法,参数字符串必须包含包名,返回Class对象。
package cp14; interface HasBatteries{} class Toy { Toy(){} Toy(int i ){} void play() { System.out.println("Play it!"); } } class FancyToy extends Toy implements HasBatteries { FancyToy(){super(1);} } public class ToyTest { static void printInfo(Class c) { System.out.println("Class name: "+c.getName());//得到该类的全名,包括包名 System.out.println("Is interface()? "+c.isInterface());//判断该类是否为接口 System.out.println("Simple name: "+c.getSimpleName());//得到该类的的简单名字,也就是类名 System.out.println("Canonical name: "+c.getCanonicalName());//得到该类的全名,包括包名 } public static void main(String[] args) { Class c=null; try { c=Class.forName("cp14.FancyToy"); } catch(ClassNotFoundException e) { System.out.println("Class not found!"); System.exit(1); } printInfo(c); for(Class face:c.getInterfaces())//得到该类实现的所有接口 { printInfo(face); } Class up=c.getSuperclass(); Object obj=null; try { //使用newInstance()来创建的类必须带有默认的构造器 obj=(Toy)up.newInstance();//由该类的Class对象创建该类的实例,必须满足该类有一个午餐构造方法 } catch(Exception e) { e.printStackTrace(); System.exit(1); } printInfo(obj.getClass()); //此时Toy对象向上转型为了Object对象,必须向下转型后才能调用Toy特有的方法 //obj.play(); ((Toy)obj).play(); } }
运行结果:
Class name: cp14.FancyToy Is interface()? false Simple name: FancyToy Canonical name: cp14.FancyToy Class name: cp14.HasBatteries Is interface()? true Simple name: HasBatteries Canonical name: cp14.HasBatteries Class name: cp14.Toy Is interface()? false Simple name: Toy Canonical name: cp14.Toy Play it!
java还提供了另一种方法来生成Class对象的引用,即使用类字面常量。类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型。另外对于基本数据类型的包装类,还有一个标准字段TYPE。TYPE字段是一个引用,指向对应的基本数据类型的Class对象,如下所示:
boolean.class | Boolean.TYPE |
char.class | Character.TYPE |
byte.class | Byte.TYPE |
short.class | Short.TYPE |
int.class | Integer.TYPE |
long.class | Long.TYPE |
float.class | Float.TYPE |
double.class | Double.TYPE |
void.class | Void.TYPE |
1)加载,这是由类加载器执行的。该步骤查找字节码,并从这些字节码中创建一个Class对象。
2)链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。
3)初始化。如果该类具有超累,则对其初始化,执行静态初始化器和静态初始化块。
如果一个static final值是“编译器常量”,那么这个值不需要对其所属类进行初始化就可以被读取。但是只是将一个域设置为static或者final的,还不足以确保这种行为。
Class引用所指向的Class对象可以进行限定,这里使用了Class的泛化语法。
当将泛型语法用于Class对象时,newInstance ()方法将返回该对象的确切类型,而不仅仅是在ToyTest.java中看到的基本的Object。
public class GenericToyTest { public static void main(String[] args) throws Exception { Class<FancyToy> ftClass=FancyToy.class; FancyToy fancyToy=ftClass.newInstance(); Class <? super FancyToy> up=ftClass.getSuperclass(); Object obj=up.newInstance(); //写成下面这种形式将无法编译,这简直不可思议 //Class <Toy> up3=ftClass.getSuperclass(); Class <Toy> up3=(Class<Toy>) ftClass.getSuperclass(); Toy obj3=up3.newInstance(); obj3.play(); } }
(2)类型转换前先做检查
某个对象是不是某个类的实例
静态检查:instanceof()
Pet pet=new Pet(); if(pet instanceOf Pet) { System.out.println("true"); }
动态检查:isInstance()
Pet pet=new Pet(); Class<? extends Pet> cla=Pet.class; if(cla.isInstance(pet)){}
(3)instanceof与Class的等价性
class Base{} class Derived extends Base{} public class FamilyVsExactType { static void test(Object x) { System.out.println("Testing x of type "+x.getClass()); System.out.println("x instanceof Base "+(x instanceof Base)); System.out.println("x instanceof Derived "+(x instanceof Derived)); System.out.println("Base isInstance(x) "+Base.class.isInstance(x)); System.out.println("Derived isInstance(x) "+Derived.class.isInstance(x)); System.out.println("x.getClass()==Base.class "+(x.getClass()==Base.class)); System.out.println("x.getClass()==Derived.class "+(x.getClass()==Derived.class)); System.out.println("x.getClass().equals(Base.class) "+(x.getClass().equals(Base.class))); System.out.println("x.getClass().equals(Derived.class) "+(x.getClass().equals(Derived.class))); } public static void main(String[] args) { test(new Base()); test(new Derived()); } }
输出结果是:
Derived isInstance(x) false x.getClass()==Base.class true x.getClass()==Derived.class false x.getClass().equals(Base.class) true x.getClass().equals(Derived.class) false Testing x of type class cp14.Derived x instanceof Base true x instanceof Derived true Base isInstance(x) true Derived isInstance(x) true x.getClass()==Base.class false x.getClass()==Derived.class true x.getClass().equals(Base.class) false x.getClass().equals(Derived.class) true
instanceof()和isInstance()结果完全一样,equals()和==也一样。instanceof保持了类型的概念,它指的是“你是这个类吗?或者你是这个类的派生类吗?”而如果使用==比较实际的Class对象,就没有考虑继承----它或者是这个确切类型,或者不是。
(4)动态代理
代理是基本的设计模式之一,它是你为了提供的额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。下面是一个用来展示代理结构的简单示例:
interface Interface { void doSomething(); void doSomethingElse(); } class RealObject implements Interface { public void doSomething() { System.out.println("do something."); } public void doSomethingElse() { System.out.println("do something else."); } } class SimpleProxy implements Interface { private Interface proxied; public SimpleProxy(Interface proxied) { this.proxied=proxied; } public void doSomething() { System.out.println("SimpleProxy do something."); proxied.doSomething(); } public void doSomethingElse() { System.out.println("SimpleProxy do something else."); proxied.doSomethingElse(); } } public class SimpleProxyDemo { static void consumer(Interface iface) { iface.doSomething(); iface.doSomethingElse(); } public static void main(String[] args) { consumer(new RealObject()); consumer(new SimpleProxy(new RealObject())); } }
输出结果是:
do something. do something else. SimpleProxy do something. do something. SimpleProxy do something else. do something else.
java的动态代理比代理的思想要向前迈进了一步,因为它可以动态创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器(InvocationHandler),他的工作是解释调用的类型并确定相应的对策。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface SomeMethods { void boring1(); void boring2(); void interesting(); void boring3(); } class Implementation implements SomeMethods { public void boring1() { System.out.println("boring1"); } public void boring2() { System.out.println("boring2"); } public void boring3() { System.out.println("boring3"); } public void interesting() { System.out.println("interesting"); } } class MethodSelector implements InvocationHandler { private Object proxied; public MethodSelector(Object proxied) { this.proxied=proxied; } @Override public Object invoke(Object proxy,Method method,Object[] args) throws Throwable { if(method.getName().equals("interesting")) { System.out.println("Proxy detected interesting method!"); } return method.invoke(proxied, args); } } public class SelectingMethod { public static void main(String[] args) { SomeMethods proxy=(SomeMethods)Proxy.newProxyInstance (SomeMethods.class.getClassLoader(), new Class[]{SomeMethods.class}, new MethodSelector(new Implementation())); proxy.boring1(); proxy.boring2(); proxy.boring3(); proxy.interesting(); } }
输出结果是:
boring1 boring2 boring3 Proxy detected interesting method! interesting
通过调用Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。
相关文章推荐
- Java学习笔记:反射与代理机制(静态、动态)
- Java的反射机制与动态代理学习笔记
- java学习笔记13--反射机制与动态代理
- 15. JAVA 反射机制 Part 2(动态代理、类的生命周期、工厂设计模式) ----- 学习笔记
- java基础学习——反射机制与动态代理
- 【Java反射学习笔记系列之jdk动态代理】静态代理和动态代理的区别以及动态代理的作用和实现
- java反射之动态代理学习笔记
- Java学习笔记之反射的应用-动态代理
- java学习之路 之 反射机制综合练习题、动态代理实例
- java学习笔记一 java类型信息(RITI和反射)
- 【Java核心技术】类型信息(Class对象 反射 动态代理)
- (54)Java学习笔记——反射 / 动态代理
- Java学习之反射机制---动态代理
- JAVA学习笔记15:动态代理
- 《Spring 3.x 企业应用开发实战》学习笔记 第三章 IoC容器概述 3.2 相关Java基础知识 类装载器 反射机制
- java学习笔记14--动态代理
- Effective Java 学习笔记(第53条:接口优先于反射机制)
- Java中的动态代理及反射机制
- java学习笔记反射机制
- c#反射机制学习和利用反射获取类型信息