天天看点

反射及动态代理01-反射反射应用

01-反射

反射是Java成为动态语言的关键

什么是反射

程序中的反射是通过对象映射到类,在程序运行期间就可以获取到类的信息(结构)

类-》对象

对象-》类

在编写程序的时候,不知道要创建的对象是谁,直到程序运行的时候,才知道要创建那个对象

Class类是专门用来描述其他类的类,Class的对象就是另外一个类结构的抽象对象

bean=com.sholin.entity.Car
    
public class Test {
    public static Properties properties = null;
    static {
        //new一个配置文件
        properties = new Properties();
        try {
            //加载配置文件
            properties.load(new FileInputStream(System.getProperty("user.dir")
                                                +"/src/com/sholin/test29/bean.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception {
        //获取目标类名
        String bean = properties.getProperty("bean");
        //根据目标类名获取目标类所对应的Class对象
        Class clazz = Class.forName(bean);
        //获取构造器(有参构造,传null,表示无参构造)
        Constructor constructor = clazz.getConstructor(String.class);
        //根据构造器创建对象(上面传null,这也得传null,否则抛异常)
        Object newInstance = constructor.newInstance("宝马");
        System.out.println(newInstance);
    }
}
           

如何使用反射

反射的源头是Class类,Java.lang.Class

Class类是专门用来描述其他类的类,Class的每一个实例化对象都是对目标类的具体描述

Class有三种获取方式

  • 通过类名获取
  • 通过类字面量获取
  • 通过对象获取
Car car = new Car();
Class clazz = car.getClass();
           

每个类的Class对象只有一个,因为每个类在内存中只加载一次,加载到内存中的类叫做运行时类,因为只能加载一次,所以每个类的运行时类只有一个

Class就是描述运行时类的,每个Clas对象就是目标类的运行时类

获取到了反射源头之后,就可以进行操作,获取类的各种信息

类的信息包括属性、方法、构造器、父类、实现的接口、所在包的名称、访问权限等

构造器

无参构造

Constructor是专门用来描述构造器的类,Constructor的对象就是目标类的构造器

public class ConstructorTest {
    public static Properties properties;
    static {
        properties = new Properties();
        try {
            properties.load(new FileInputStream(System.getProperty("user.dir")+"/src/com/sholin/test29/bean.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception {
        //方式一:对象名获取
        String bean = properties.getProperty("bean");
        Class clazz = Class.forName(bean);
        Class clazz1 = Class.forName("com.sholin.test29.Car");
        //方式二:字面量获取
        Class clazz2 = Car.class;
        //方式三:创建对象获取
        Car car = new Car();
        Class clazz3 = car.getClass();
        //获取无参构造器getConstructor()
        Constructor constructor = clazz.getConstructor(null);
        //创建对象newInstance()
        Object instance = constructor.newInstance(null);
        System.out.println(instance);
    }
}
           

有参构造

public class ConstructorTest {
    public static Properties properties;
    static {
        properties = new Properties();
        try {
            properties.load(new FileInputStream(System.getProperty("user.dir")+"/src/com/sholin/test29/bean.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception {
        //方式一:对象名获取
        String bean = properties.getProperty("bean");
        Class clazz = Class.forName(bean);
        Class clazz1 = Class.forName("com.sholin.test29.Car");
        //方式二:字面量获取
        Class clazz2 = Car.class;
        //方式三:创建对象获取
        Car car = new Car();
        Class clazz3 = car.getClass();
//        Constructor constructor = clazz.getConstructor(null);
//        Object instance = constructor.newInstance(null);
        //有参构造 传入参数类型
        Constructor constructor = clazz.getConstructor(String.class);
        //创建对象,传递参数值
        Object instance = constructor.newInstance("宝马");
        System.out.println(instance);
    }
}
           

属性

//获取所有共有属性 getFields()  无视访问权限, getDeclaredFields()
Field[] fields = clazz.getFields();
for (Field field : fields) {
    System.out.println(field);
}
//name属性私有,无法获取
Field name = clazz.getField("name");
//无视访问权限 getDeclaredField()
Field name1 = clazz.getDeclaredField("name");
System.out.println(name1);
           

获取属性的目的就是给对象赋值,首先通过构造器创建对象,接下来通过属性给对象赋值

方法

//获取所有共有方法 getMethods();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    System.out.println(method);
}
//无参构造
Constructor constructor = clazz.getConstructor(null);
Object instance = constructor.newInstance(null);
System.out.println("*************方法设值**************");
//getMethod获取方法
Method setName = clazz.getMethod("setName",String.class);
//传递参数
setName.invoke(instance, "宝马");
System.out.println(instance);
           

反射应用

在程序运行过程中动态创建对象

  1. 在配置问价那种定义类的信息
  2. 动态读取配置文件,创建对象
    public class Test {
        public static Properties properties = null;
        static {
            //new一个配置文件
            properties = new Properties();
            try {
                //加载配置文件
                properties.load(new FileInputStream(System.getProperty("user.dir")+"/src/com/sholin/test29/bean.properties"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) throws Exception {
            //获取目标类名
            String bean = properties.getProperty("bean");
            //根据目标类名获取目标类所对应的Class对象
            Class clazz = Class.forName(bean);
            //获取构造器
            Constructor constructor = clazz.getConstructor(null);
            //根据构造器创建对象
            Object newInstance = constructor.newInstance(null);
            System.out.println(newInstance);
        }
    }
               

动态代理

动态代理主要通过反射完成

代理模式

代理模式是一种常用的Java设计模式,代理模式是指在处理一个业务的时候,通过代理的方式来完成

委托方和代理方,委托方委托代理帮助完成某些工作(就像外包公司一样,核心的功能自己完成,其余的交给外包公司帮忙做)

在所有的代理模式中,委托方和代理方有一个共性,双方都具备完成需求的能力

Java中将对象所具备的能力封装成接口,Java中的代理模式的原则就是委托类和代理类实现了同样的接口

动态代理

代理类和委托类之间通过依赖注入进行关联,在设计程序时,需要将委托类定义为代理类的成员变量。

代理类本身并不会取执行业务逻辑,而是通过调用委托类的方法来完成,真正的业务逻辑仍然时委托类来完成,代理类只是完成一些核心业务意外的功能,这样实现解耦合

一个完整的业务包含:核心业务模块+辅助性的业务(打印日志、消息过滤、类型转换)

委托类只需要负责核心业务,不需要参杂任何与核心业务无关的代码

辅助性的业务有代理类完成,将委托类注入到代理类中,分别完成核心业务和辅助性业务

开发者只需要调用代理对象即可完成整套业务

静态代理

静态代理是指代类提前写好的,动态代理是指代理类时动态生成的

静态代理

public class ProxyTest {
    public static void main(String[] args) {
		//创建对象
        BaoMa baoMa = new BaoMa();
        //Car代理类
        ProxyCar proxyCar = new ProxyCar(baoMa);
        System.out.println(proxyCar.saleCar());
		//同上,代码冗余,耦合度高
        Audi audi = new Audi();
        ProxyCar proxyCar1 = new ProxyCar(audi);
        System.out.println(proxyCar1.saleCar());
    }
}
//Car代理类
public class ProxyCar implements Car {
    private Car car;
    public ProxyCar(Car car) {
        this.car = car;
    }
    @Override
    public String saleCar() {
        System.out.println("启动代理销售汽车");
        return this.car.saleCar();
    }
}
//Car接口
public interface Car {
    public String saleCar();
}
//实现类
public class BaoMa implements Car {
    @Override
    public String saleCar() {
        return "销售宝马汽车";
    }
}
           

动态代理实现

指定代理类的生成策略

通过java.lang.reflect.InvocationHandler接口,可以在程序运行期间动态生成代理类,即生成策略通过接口来完成

实现InvocationHandler接口,Porxy.newProxyInstances()三个参数

  • 类加载器ClassLoader
  • 委托类的接口
  • 当前InvocationHandler实例对象(动态代理方法在执行时,会调用h里面的invoke方法去执行)

动态生成一个类,代理类

代理类要调用委托类的接口,必须首先获取委托类的接口,所以要传入委托类的接口

类需要类加载器将动态生成的代理类加载到Java内存中才能使用,所以要传入ClassLoader

上述过程需要一个对象完成,即当前实例对象

如下代码实现通过动态代理方式生成不同对象,执行彼此功能

public class MyInvocationHandler implements InvocationHandler {
    private Object obj=null;
    public Object bind(Object obj){
        this.obj = obj;
        return Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(),obj.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //核心业务代码委托对象来完成,方法由委托对象调用
        System.out.println("启动动态代理模式");
        Object invoke = method.invoke(this.obj, args);
        return invoke;
    }
}

public class Test {
    public static void main(String[] args) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        //定义委托类
        Car car = new Audi();
        //获取动态代理对象
        Car proxy = (Car)myInvocationHandler.bind(car);
        System.out.println(proxy.saleCar());

        //定义委托类
        Phone phone = new Huawei();
        //获取动态代理对象
        Phone proxy1 = (Phone) myInvocationHandler.bind(phone);
        System.out.println(proxy1.salePhone());
    }
}

//Car接口
public interface Car {
    public String saleCar();
}
//Car接口实现(核心任务)
public class BaoMa implements Car {
    @Override
    public String saleCar() {
        return "销售宝马汽车";
    }
}
//Phone接口及接口实现
public interface Phone {
    public String salePhone();
}
public class Huawei implements Phone {
    @Override
    public String salePhone() {
        return "销售华为手机";
    }
}