Thinking In Java Part08(newInstance、instanceof、动态代理)

1、newInstance
	Class的newInstance()是实现“虚拟构造器”的一种途径,虚拟构造器允许你声明:我不知道你的确切类型,但是无论如何要正确地创建你自己。使用newInstance()来创建的类,必须带有默认的构造器。
2、类字面常量
	一种为Class.forname("xxx"),Java还提供了另一种方法生成对Class对象的引用,使用类字面常量。即Cookie.class
	当使用".class"来创建对Class对象的引用时,不会自动地初始化该Class对象。为了使用类而做的准备工作实际包含三个步骤:
		2.1、加载,由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必须的),并从这些字节码中创建一个Class对象。
		2.2、链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
		2.3、初始化。如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。
		初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用才执行。
3、instanceof与Class的等价性
	class Base {
	}

	class Derived extends Base {
	}

	public class InstanceofAndClass {
	    static void test(Object x) {
	       static void test(Object x) {
	        //base Derived
	        System.out.println("Testing x of type:" + x.getClass());
	        //true true
	        System.out.println("x instanceof Base:" + (x instanceof Base));
	        //false true
	        System.out.println("x instanceof Derived:" + (x instanceof Derived));
	        //true  true
	        System.out.println("Base.isInstance(x):" + Base.class.isInstance(x));
	        //false true
	        System.out.println("Derived.isInstance(x):" + Derived.class.isInstance(x));
	        //true false
	        System.out.println("x.getClass() ==Base.class:" + (x.getClass() == Base.class));
	        //false true
	        System.out.println("x.getClass() ==Derived.class:" + (x.getClass() == Derived.class));
	        //true false
	        System.out.println("x.getClass().equals(Base.class):" + (x.getClass().equals(Base.class)));
	        //false true
	        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());
	    }
	}

	instanceof和isInstance()生成的结果完全一样,equals()和==也一样。但是测试的结论却不同。instanceof保持了类型的概念,指的是“你是这个类吗,或者你是这个类的派生类吗?”,而如果用==比较实际的Class对象,就没有考虑继承——它或者是这个确切的类型,或者不是。
4、反射,运行时的类信息
	如果不知道某个对象的确切类型,RTTI可以告诉你,但是需要这个类型在编译时必须已知,这样才能使用RTTI识别它,并利用这些信息做一些有用的事。也就是编译时编译器必须知道所有要通过RTTI来处理的类。
	如果从磁盘文件或者网络连接中获取了一串字节【RMI,允许一个Java程序将对象分布到多态机器上】,并且被告知这些字节代表了一个类,我们怎么去使用在编译器为我们的程序生成代码之后很久才出现的这个类?
	Class类和java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了Field、Method、Constructor类(每个类都实现了Member接口)。这些类型的对象是由JVM在运行时创建的,用以表示未知类里对应的成员。这样就可以使用Constructor创建新的对象,用get和set方法读取和修改和Field对象关联的对象,用invoke方法调用与Method对象关联的方法。另外,还可以调用getField、getMethods、getConstructors等便利的方法,以返回表示字段、方法以及构造器的对象的数组。这样的话匿名对象的类信息就能在运行时被完全确定下来,而且在编译时不需要知道任何事情。
	当通过反射和一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类(就像RTTI)。在用他做其他事情之前必须先加载那个类的CLass对象。RTTI和反射之间真正的区别只在于:对RTTI来说,编译器在编译时打开和检查.class文件(我们可以用“普通”方式调用对象的所有方法)。对于反射机制来说,.class文件在编译时是不可获取的,所以在运行时打开和检查.class文件。
5、动态代理
	代理是基本的设计模式之一,为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。代理通常充当着中间人的角色。
	interface Interface {
	    void doSomething();

	    void somethingElse(String arg);
	}

	class RealObject implements Interface {

	    @Override
	    public void doSomething() {
	        System.out.println("doSomething");
	    }

	    @Override
	    public void somethingElse(String arg) {
	        System.out.println("somethingElse" + arg);
	    }
	}

	class SimpleProxy  implements Interface{
	    private Interface proxied;
	    public SimpleProxy(Interface proxied){
	        this.proxied = proxied;
	    }
	    @Override
	    public void doSomething() {
	        System.out.println("SimpleProxy doSomething");
	        proxied.doSomething();
	    }

	    @Override
	    public void somethingElse(String arg) {
	        System.out.println("SimpleProxy somethingElse" + arg);
	        proxied.somethingElse(arg);
	    }
	}
	public class SimpleProxyDemo{
	    public static void consumer(Interface ifce){
	        ifce.doSomething();
	        ifce.somethingElse("boo");
	    }
	    public static void main(String[] args) {
	        consumer(new RealObject());
	        consumer(new SimpleProxy(new RealObject()));
	    }
	}
	因为consumer()接受的是Interface,所以它无法知道正在获得的倒地是RealObject还是Simpleproxy,因为两者都实现了Interface。但是SimpleProxy已经被插入到了客户端和RealObject之间,因此她会执行操作,然后调用RealObject上相同的方法。
	任何时刻,你想要将额外的操作从“实际”对象中分离到不同的地方,特别是当你希望能够很容易地做出修改,从没有使用额外操作转为使用这些操作,或者反过来时,代理就很有用(设计模式的关键就是封装修改)。代理使得我们可以很容易地添加或移除其他额外操作的代码。
	Java动态代理可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。
	public class SimpleDynamicProxyDemo{
	    public static void consumer(Interface ifce){
	        ifce.doSomething();
	        ifce.somethingElse("boo");
	    }
	    public static void main(String[] args) {
	        RealObject realObject = new RealObject();
	        consumer(realObject);
	        Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(realObject));
	        consumer(proxy);
	    }
	}

	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(" " +args);
	            }
	        }
	        return method.invoke(proxied,args);
	    }
	}
	通过调用静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给他),一个你希望该代理实现的接口列表(不能是类或抽象类),以及Invocationhandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个“实际”对象的引用,从而使得调用处理器在执行其中介任务时,可以将请求换发。
    invoke方法中传递进了代理对象,以防你需要区分请求的来源,但是在许多情况下,你并不关心这一点。然而,在invoke内部,在代理上调用方法时需要格外当心,因为对接口的调用将被重定向为对代理的调用。
	在invoke之前可以通过传递其他的参数,来过滤某些方法调用
	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);
    }
第一个参数proxy是动态代理文件不能直接用于invoke,是用来区分来源,需要使用在新建时绑定的对象proxied。
因为生成的动态代理文件 会自动继承Proxy 所以jdk动态代理不能对类,只能对接口实现代理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值