第十四章 类型信息 反射 动态代理 空对象 接口和类型信息

1.反射:运行时的类信息

  • RTTI:运行时得知对象的具体类型,但这个类型必须在编译时已知,也就是说,编译器必须知道所有要通过RTTI来处理的类。
  • 特殊的情况:获取一个并不在本程序中的对象的引用,编译时程序无法得知这个对象所属的类:例如从磁盘文件或网络中获取到一串代表一个类的字节码。
  • IDE(集成开发环境):“基于构建的编程”,“快速应用开发(RAD)的应用构建工具”。
  • RMI(远程方法调用)和分布式:希望提供在跨网络的远程平台上创建和运行对象的能力。允许一个Java程序将对象分布到多台机器上。如大量计算任务等。
  • Class类与java.lang.reflect类库:它们一起对反射的概念进行了支持,java.lang.reflect类库包含了Field(参数)Method(方法)以及Constructor(构造方法)类。这些类型由JVM在运行时创建的,用以表示未知类里对应的成员。可以使用Consturctor创建新的对象,用get()和set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。可以调用getFields()、getMethods()、getConstructors()以返回表示字段、方法以及构造器的对象的数组。这样匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情
  • RTTI和反射的区别:当通过反射机制与一个未知类型的对象打交道时,JVM只是简单检查这个对象,看这个对象属于哪个特定的类。
    在用这个对象之前必须先加载这个类的Class对象(包含这个类的所有信息,由字节码文件中的字节码生成)。因此JVM必须获得这个类的.class文件:从网络或本地。
    所以,RTTI和反射之间的真正区别是:RTTI:编译器在编译时打开和检查.class文件。反射:.class文件在编译时是不可获取的,是在运行时打开和检查.class文件。

1.1类方法提取器,反射机制中方法的简单使用

  • 动态的获取某个类的信息。
  • 浏览实现了类定义的源码和jdk文档,只能找到在这个类定义中被定义或被覆盖的方法,但父类中的许多更有用的方法时很难找到的
    public class ShowMethods {
    	private static String usage = 
    			"usage:\n"+
    	"ShowMethods qualified.class.name:\n"+
    				"To show all methods in class or:\n"+
    	"ShowMethods qualified.class.name word\n"+
    				"To search for methods involving 'word'";
    	private static Pattern p = Pattern.compile("\\w+\\.");//一个正则表达式
    	public static void main(String[] args) {
    		if (args.length < 1) {
    			System.out.println(usage);
    			System.exit(0);
    		}
    		int lines = 0;
    		try {
    			Class<?> c = Class.forName(args[0]);//获取到类
    			//获取所有方法 
    			Method[] methods = c.getMethods();
    			//获取所有构造器
    			Constructor[] ctors = c.getConstructors();
    			if (args.length == 1) {
    				for(Method method : methods)
    					System.out.println(p.matcher(method.toString()).replaceAll(""));
    				for(Constructor ctor : ctors)
    					System.out.println(p.matcher(ctor.toString()).replaceAll(""));
    				lines = methods.length + ctors.length;
    			}else{
    				for(Method method : methods)
    					if (method.toString().indexOf(args[1]) != -1) {
    						System.out.println(p.matcher(method.toString()).replaceAll(""));
    						lines++;
    					}
    				for(Constructor ctor : ctors)
    					if (ctor.toString().indexOf(args[1]) != -1) {
    						System.out.println(p.matcher(ctor.toString()).replaceAll(""));
    						lines++;
    					}
    			}
    		} catch (ClassNotFoundException e) {
    			System.out.println("No such class: " + e);
    			e.printStackTrace();
    		}
    	}
    }
    /**这个类中的所有公共方法 包括父类当中可用的方法,如果要获取私有的方法可以使用getde....methods()
    public static void main(String[])
    public final void wait() throws InterruptedException
    public final void wait(long,int) throws InterruptedException
    public final native void wait(long) throws InterruptedException
    public boolean equals(Object)
    public String toString()
    public native int hashCode()
    public final native Class getClass()
    public final native void notify()
    public final native void notifyAll()
    public ShowMethods()//构造方法
     */
    
  • 上面的构造方法是编译器自动合成的,该自动合成的默认构造器会自动被赋予与类一样的访问权限

2.动态代理

  • 代理是基本的设计模式之一。使用插入的对象代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。
  • 一段简单的代码
    interface Interface{
    	void doSomething();
    	void somethingElse(String arg);
    }
    /**
     * 实际的类
     */
    class RealObject implements Interface{
    	public void doSomething() {System.out.println("真实类 doSomething方法");}
    	public void somethingElse(String arg) {System.out.println("真实类somethingElse方法 " + arg);}
    }
    /**
     * 代理类
     */
    class SimpleProxy implements Interface{
    	private Interface proxied;
    	public SimpleProxy(Interface proxied) {
    		this.proxied = proxied;
    	}
    	public void doSomething() {
    		System.out.println("代理类的 doSomething方法 ");
    		proxied.doSomething();
    	}
    	public void somethingElse(String arg) {
    		System.out.println("代理类的 somethingElse方法  " + arg);
    		proxied.somethingElse(arg);
    	}
    }
    public class SimpleProxyDemo {
    	public static void consumer(Interface iface){
    		iface.doSomething();
    		iface.somethingElse("bonobo");
    	}
    	public static void main(String[] args) {
    		consumer(new RealObject());//直接使用真实类
    		consumer(new SimpleProxy(new RealObject()));//使用代理类
    	}
    }
    /**
     真实类 doSomething方法
    真实类somethingElse方法 bonobo
    代理类的 doSomething方法 
    真实类 doSomething方法
    代理类的 somethingElse方法  bonobo
    真实类somethingElse方法 bonobo
     */ 
    

2.1java的动态代理

  • java的动态代理比代理思想更向前迈进了一步。它可以动态的创建代理并动态的处理对所代理方法的调用。
  • 在动态代理上所做的所有调用都会被重新定向到单一的调用处理器上。看使用吧。
    class DynamicProxyHandler implements InvocationHandler{
    	private Object proxied;
    	public DynamicProxyHandler(Object proxied) {
    		this.proxied = proxied;
    	}
    	
    	/**
    	 * 当调用动态代理的方法时会重定向到这里
    	 * 第一个参数:代理类
    	 * 第二个参数:代理的方法
    	 * 第三个参数:方法传递的形式参数列表
    	 */
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		System.out.println("**** proxy: " + proxy.getClass() +
    				".method: " + method + ".args: " + args);
    		if (args != null) 
    			for(Object arg : args)
    				System.out.println("   " + arg);
    			return method.invoke(proxied, args);//反射执行实际对象的方法
    	}
    }
    public class SimpleDynamicProxy {
    	public static void consumer(Interface iface){
    		iface.doSomething();
    		iface.somethingElse("bonobo");
    	}
    	public static void main(String[] args) {
    		RealObject real = new RealObject();
    		consumer(real);//直接执行真实的类
    		System.out.println();
    		//使用动态代理 创建一个代理实例 方法的调用重定向到DynamicProxyHandler
    		Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), 
    				new Class[]{Interface.class}, new DynamicProxyHandler(real));
    		consumer(proxy);
    	}
    }
  • 使用newProxyInstance()创建动态代理对象,第一个参数,类加载器;第二个参数:希望代理实现的接口列表;第三个参数:InvocationHandler接口的一个实现。
  • 执行被代理对象的操作,使用invoke()方法,可以通过传递其他参数过滤某些方法调用:
    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 the interesting method");
    		return method.invoke(proxied, args);//反射执行代理类的方法
    	}
    }
    interface SomeMethods{
    	void boring1();
    	void boring2();
    	void interesting(String arg);
    	void boring3();
    }
    class Implementation implements SomeMethods{
    	@Override
    	public void boring1() {System.out.println("boring1");}
    	@Override
    	public void boring2() {System.out.println("boring2");}
    	@Override
    	public void interesting(String arg) {System.out.println("interesting " + arg);}
    	@Override
    	public void boring3() {System.out.println("boring3");}
    }
    public class SelectingMethods {
    	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.interesting("bonobo");
    		proxy.boring3();
    	}
    }
    /**
    boring1
    boring2
    Proxy detected the interesting method
    interesting bonobo
    boring3
     */

3.空对象

++一种编程逻辑 不做解释看书吧

3.1模拟对象与桩

++-不做解释看书吧

4.接口与类型信息

看书吧 也是一种编程逻辑

总结





































































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值