【JavaSE】反射

尚硅谷JavaSE笔记合集

文章名链接
【JavaSE】异常文章地址
【JavaSE】常用类:String、LocalDateTime…文章地址
【JavaSE】枚举文章地址
【JavaSE】注解文章地址
【JavaSE】集合框架文章地址 | HashMap源码解析 | List相关实现类源码解析
【JavaSE】泛型文章地址
【JavaSE】IO流文章地址 | 字符编码详解
【JavaSE】网络编程,BIO需求演进文章地址
【JavaSE】反射文章地址
【JavaSE】jdk8新特性文章地址

一、反射概述

1.1 概述

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

在这里插入图片描述

动态语言、静态语言

  • 动态语言
    • 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。
    • 主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。
  • 静态语言
    • 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如 Java、C、C++。

Java

  • Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!
  • Java反射机制提供的功能
    • 在运行时判断任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判断任意一个类所具有的成员变量和方法
    • 在运行时获取泛型信息
    • 在运行时调用任意一个对象的成员变量和方法
    • 在运行时处理注解
    • 生成动态代理
  • 反射相关的主要API
    • java.lang.Class:代表一个类
    • java.lang.reflect.Method:代表类的方法
    • java.lang.reflect.Field:代表类的成员变量
    • java.lang.reflect.Constructor:代表类的构造器

1.2 简单应用

Person

public class Person {
    public int age;
    //私有
    private String name;	
    //私有
    private Person(int age){	
        this.age=age;
    }
    //私有
    private void show(){	
        System.out.println("私有show");
    }
    
    public Person() {
    }
    public void play(){
        System.out.println("公共play");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类

/**
 * 举例三种场景实现下列操作:
 *      1.创建person对象
 *      2.对person对象的属性进行重写赋值
 *      3.调用person对象中的方法
 */
public class ApplicationTest {
    //第一种场景:new 公共结构。在Person类的外部,不可以通过Person类的对象调用其内部私有的结构。
    @Test
    public void test1(){
        //1.创建person对象
        Person p=new Person();
        //2.对person对象的属性进行重写赋值
        p.age=2;
        System.out.println(p);
        //3.调用person对象中的方法
        p.play();
    }
    //第二种场景:反射公共结构
    @Test
    public void test2() throws Exception {
        Class<Person> clazz = Person.class;
        //1.创建person对象
        Constructor<Person> constructor1 = clazz.getDeclaredConstructor();
        Person p = constructor1.newInstance();
        //2.对象的属性进行重新赋值
        Field age = clazz.getDeclaredField("age");
        age.set(p,2);
        System.out.println(p);
        //3.调用person对象中的方法
        Method play = clazz.getDeclaredMethod("play");
        play.invoke(p);
    }
    @Test
    //第三种场景:反射私有结构
    public void test3() throws Exception{
        Class<Person> clazz = Person.class;
        //1.创建person对象
        Constructor<Person> constructor3 = clazz.getDeclaredConstructor(int.class);
        constructor3.setAccessible(true);
        Person p = constructor3.newInstance(2);
        //2.对象的属性进行重新赋值
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p,"Jim");
        System.out.println(p);
        //3.调用person对象中的方法
        Method show = clazz.getDeclaredMethod("show");
        show.setAccessible(true);
        show.invoke(p);
    }
}

1.3 产生疑问

/**
 * 疑问1:直接new和反射都可以调用公共的结构,开发中到底用那个?
 * 		建议:直接new的方式。
 * 疑问2:什么时候会使用反射的方式?
 * 		- 在代码运行过程中才能确定需要哪个类时。体现反射的特征:动态性。
 * 		- 如web服务器:运行时,根据url请求判断需要调用哪个类创建实例
 * 疑问3:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
 * 		不矛盾。面向对象强调不建议调私有结构,反射强调能不能调。
 */

二、Class类与Class实例

2.1 Class类的理解

/**
 * 关于java.lang.Class类的理解
 * 	1.类的加载过程:
 * 		- 源文件(.java) 经过Javac.exe命令后,会生成一个或多个字节码文件(.class)。
 * 		- 使用java.exe命令对某个字节码文件进行解释运行。
 *		  相当于将某个字节码文件加载到内存中。此过程就称为类的加载。
 * 		  加载到内存中的类,我们就称为运行时类。此运行时类,就作为Class的一个实例。即类本身就是一个对象。
 * 		
 *	2.换句话说,Class的实例就对应着一个运行时类。
 * 
 */

Class类的常用方法

在这里插入图片描述

2.2 获取Class实例

/**
 *  获取Class实例的四种方式:即加载到内存中的类(运行时类)
 *      1.Class.forName("类路劲")   推荐使用
 *      2.类名.Class
 *      3.对象.getClass()
 *      4.类名.class.getClassLoader().loadClass()
 *  加载到内存中的运行时类,会缓存一定的时间。此时,通过不同的方式获取此运行时类都是同一个。
 */
public class GetInstance {
    @Test
    public void test() throws Exception {
        //1.Class.forName("类路劲")   推荐使用
        Class clazz1=Class.forName("org.example.java.classInstance.Person");
        //2.类名.Class
        Class clazz2=Person.class;
        //3.对象.getClass()
        Person p=new Person();
        Class clazz3 = p.getClass();
        //4.类名.class.getClassLoader().loadClass()
        Class clazz4 = GetInstance.class.getClassLoader().loadClass("org.example.java.classInstance.Person");

        System.out.println(clazz1==clazz2); //true
        System.out.println(clazz2==clazz3); //true
        System.out.println(clazz3==clazz4); //true
    }
}

2.3 Class实例有哪些?

/**
 * Class实例可以有哪些类型?
 *      1.普通类:外部类,成员内部类,静态内部类,局部内部类,匿名内部类
 *      2.接口、抽象类、枚举类,注解
 *      3.数组:类型、维度一样就是同一个Class
 *      4.基本数据类型:byte,short,char,int,long,float,double,boolean
 *      5.void
 */
public class WhitchInstance {
    @Test
    public void test(){
        class PartDemo{}
        class PartDemo{}
        //1.普通类:外部类,成员内部类,静态内部类,局部内部类,匿名内部类
        Class c1=Outer.class;
        Class c2=Outer.Inner.class;
        Class c3=Outer.InnerStatic.class;
        Class c4=PartDemo.class;
        Class c5=new Outer().getClass();
        //2.接口、抽象类、枚举类,注解
        Class c6=Function.class;
        Class c7=AbstractDemo.class;
        Class c8=EnumDemo.class;
        Class c9=Override.class;
        //3.数组:只要类型、维度一样就是同一个Class
        //即 new int[1].getClass()==new int[2].getClass()
        Class c10 = int[].class;
        //4.基本数据类型:byte,short,char,int,long,float,double,boolean
        Class c11=byte.class;
        //5.void
        Class c12=void.class;
    }
}
public class Outer {
    static class InnerStatic{}
    class Inner{}
}

三、类加载与类加载器

3.1 类加载的过程

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。

在这里插入图片描述

  • 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口(即引用地址)。所有需要访问和使用类数据只能通过这个Class对象。这个加载的过程需要类加载器参与。
  • 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
    • 验证:确保加载的类信息符合JVM规范,例如:以cafe开头,没有安全方面的问题
    • 准备:正式为类变量(static)分配内存并设置默认初始值的阶段,这些内存都将在方法区中进行分配。
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
  • 初始化:
    • 执行类构造器方法(非创建对象的构造方法)的过程:给类变量(static)赋值
      • 类构造器方法:由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
    • 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
/**
 *  1.加载
 *  2.链接:给类变量设置默认值
 *      m=0
 *  3.初始化:执行类构造器方法<clinit>(),给类变量赋值
 *      <clinit>(){     按顺序合并赋值语句
 *          m=1;
 *          m=2;
 *      }
 */
public class Test1 {
    public static void main(String[] args) {
        System.out.println(Test1.m);
    }
    static {
        m=1;
    }
    static int m=2;
}

3.2 初始化的时机

  • 类的主动引用(一定会发生类的初始化)
    • 虚拟机启动时指定的main方法所在的类
    • new类的对象
    • 调用类的静态成员(除了final常量)和静态方法
    • 对类进行反射调用
    • 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
  • 类的被动引用(不会发生类的初始化)
    • 当访问一个静态域时,只有真正声明这个域的类才会被初始化
      • 当通过子类引用父类的静态变量,不会导致子类初始化
    • 通过数组定义类引用,不会触发此类的初始化
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

3.3 类加载器

在这里插入图片描述

  • 类加载器的作用:

    • 类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
    • 类缓存:标准的JavaSE类加载器可以按要求查找类,一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
  • 类加载器的类型

    /**
     *  类加载器的类型:
     *      1.引导类加载器(Bootstrap):
     *          - C++编写,JVM自带的类加载器。无法直接获取:null
     *          - 负责Java核心库:java.lang
     *      2.扩展类加载器(Extension):ExtClassLoader
     *          -负责 jre/lib/ext 目录下的jar包,或 -D java.ext.dirs 指定目录下的jar包
     *      3.系统类加载器(System):AppClassLoader
     *          - 负责 java -classpath 或 -D java.class.path 指定目录下的类与jar包
     *          - 最常用
     */
    public class Test2 {
        public static void main(String[] args) {
            ClassLoader classLoader1 = String.class.getClassLoader();
            System.out.println(classLoader1);   //1.引导类加载器(Bootstrap):null
            ClassLoader classLoader2 = DNSNameService.class.getClassLoader();
            System.out.println(classLoader2);   //2.扩展类加载器(Extension):ExtClassLoader
            ClassLoader classLoader3 = Test2.class.getClassLoader();
            System.out.println(classLoader3);   //3.系统类加载器(System):AppClassLoader
        }
    }
    

3.4 使用类加载器

/**
 * 注意:两种方式加载文件的路径是不一样的
 */
public class Test3 {
    @Test
    public  void demo1() throws IOException {
        Properties jdbc=new Properties();
        //1.加载target/classes/jdbc.properties
        InputStream is = Test3.class.getClassLoader().getResourceAsStream("jdbc.properties");
        jdbc.load(is);
        System.out.println(jdbc.getProperty("username")+"="+jdbc.getProperty("password"));
    }
    @Test
    public  void demo2() throws IOException {
        Properties jdbc=new Properties();
        //2.加载target/jdbc.properties
        InputStream is = new FileInputStream("jdbc.properties");
        jdbc.load(is);
        System.out.println(jdbc.getProperty("username")+"="+jdbc.getProperty("password"));
    }
}

四、反射创建对象

4.1 说明

/**
 *  1.clazz.newInstance():调用运行时类的空参构造器创建对象
 *  要求:
 *      - 运行时类必须提供空参构造器
 *      - 空参构造器权限得够。通常设置为public
 *  2.在javabean中要求提供一个public的空参构造器。原因:
 *      - 便于通过反射创建运行时类的对象
 *      - 便于子类继承此运行时类,默认调用super()时,保证父类有此构造器
 *  3.直接newInstance与获取构造器创建实例相比有什么好处?
 *      - 直接newInstance有公用性,调用的都是空构造器。
 */
public class Demo1 {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Class<String> clazz = String.class;
        String s = clazz.newInstance();
        System.out.println(s);
    }
}

4.2 反射的动态性

/**
 *  体会反射的动态性
 */
public class Demo2 {
    //随机创建运行时类对象
    @Test
    public void test1() throws Exception {
        for (int i=0;i<100;i++) {
            int random= new Random().nextInt(3); //0,1,2
            switch (random){
                case 0:
                    System.out.println(getInstance("org.example.java.classLoad.Test1"));
                    break;
                case 1:
                    System.out.println(getInstance("org.example.java.classLoad.Test2"));
                    break;
                case 2:
                    System.out.println(getInstance("org.example.java.classLoad.Test3"));
                    break;
            }
        }
    }
    //指定运行时类创建对象:指定全类名
    public Object getInstance(String path) throws Exception {
        return Class.forName(path).newInstance();
    }
}

五、获取运行时类的完整结构

5.0 Person类

1、Person类

@MyAnnotation
public class Person extends Organism<String,Integer> implements Comparable<String>,MyInterface{
    private int id;
    private String name;
    private static int age; 
    public Person() {
    }
    private Person(String name) {
        this.name = name;
    }
    public void play(){
        System.out.println("玩耍");
    }
    private static void work(){
        System.out.println("工作");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
class Organism <T1,T2>{
    public T1 t;
    public void eat(String food, Date time)throws NullPointerException,ClassCastException{
        System.out.println("补充营养");
    }
    public void move(){
        System.out.println("移动位置");
    }
}
interface MyInterface{

}
@Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value() default "Hello";
}

5.1 获取属性结构

public class Test1 {
    //1.获取属性结构:public String str
    @Test
    public void test1() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        //获取运行时类和父类的public属性
        Field[] fields1 = clazz.getFields();
        for (Field field : fields1) {
            outFieldStructure(field);
        }
    }
    //根据Field对象输出属性的结构:public String str
    public void outFieldStructure(Field field){
        //访问修饰符
        String s = Modifier.toString(field.getModifiers());
        //获取类型
        String name = field.getType().getName();
        //属性名
        System.out.println(s+" "+name+" "+field.getName());
    }
}

5.2 获取方法结构

public class Test1 {
	//2.获取运行时类和父类中public的方法结构:
    //public void test(String str,int i)throws NullPointerException,ClassCastException
    @Test
    public void test2() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        Method[] methods1 = clazz.getMethods();
        for (Method method : methods1) {
            outMethodStructure(method);
        }
    }
    //根据method对象输出方法的结构:public void test(String str,int i)
    public void outMethodStructure(Method method){
        String result="";
        //访问修饰符
        String modifier = Modifier.toString(method.getModifiers());
        //返回值
        String returnType = method.getReturnType().getName();
        //方法名
        String name = method.getName();
        result=modifier+" "+returnType+" "+name+"(";
        //形参列表
        Parameter[] parameters = method.getParameters();
        if (parameters.length<=0){
            result=result+")";
        }
        for (int i=0;i<parameters.length;i++) {
            String paraType = parameters[i].getType().getName();
            String paraName = parameters[i].getName();
            if(i==parameters.length-1){
                result=result+paraType+" "+paraName+")";
                break;
            }
            result=result+paraType+" "+paraName+",";
        }
        //异常信息
        Class[] exceptionTypes = method.getExceptionTypes();
        if (exceptionTypes.length>0){
            result=result+"throws ";
            for (int i=0;i<exceptionTypes.length;i++) {
                if(i==exceptionTypes.length-1){
                    result=result+exceptionTypes[i].getName();
                    break;
                }
                result=result+exceptionTypes[i].getName()+",";
            }
        }
        System.out.println(result);
    }
}

5.3 获取构造器结构

public class Test1 {
    //3.获取构造器结构
    @Test
    public void test3() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
    }
}

5.4 获取父类及父类的泛型

public class Test1 {
    //4.获取父类及父类的泛型
    @Test
    public void test4() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        //父类:class org.example.java.getStructure.Organism
        Class superclass = clazz.getSuperclass();
        //父类+泛型:org.example.java.getStructure.Organism<java.lang.String, java.lang.Integer>
        ParameterizedType genericSuperclass = (ParameterizedType) clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
        //父类的泛型:class java.lang.String、class java.lang.Integer
        Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.print(actualTypeArgument);
        }
    }
}

5.5 获取接口、包、注解等

public class Test1 {
    //5.获取接口、包、注解等
    @Test
    public void test5() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        //接口
        Class[] interfaces = clazz.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);
        }
        //包
        System.out.println(clazz.getPackage());
        //注解
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
    }
}

六、调用运行时类的指定结构

6.0 Person类

@MyAnnotation
public class Person extends Organism<String,Integer> implements Comparable<String>,MyInterface{
    private int id;
    private String name;
    private static int age;
    public Person() {
    }
    private Person(String name) {
        this.name = name;
    }
    public void play(){
        System.out.println("玩耍");
    }
    private static void work(){
        System.out.println("工作");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
class Organism <T1,T2>{
    public T1 t;
    public void eat(String food, Date time)throws NullPointerException,ClassCastException{
        System.out.println("补充营养");
    }
    public void move(){
        System.out.println("移动位置");
    }
}
interface MyInterface{

}
@Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value() default "Hello";
}

6.1 构造器

/**
 *  1.调用运行时类的构造器
 *      - 私有构造器
 *  2.调用运行时类的方法
 *      - 成员方法
 *      - 静态方法
 *  3.调用运行时类的属性
 *      - 成员属性
 *      - 静态属性
 */
public class Test1 {
    //3.调用运行时类的构造器
    @Test
    public void test1() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        //私有构造器
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance("name");
        System.out.println(o);
    }
}

6.2 方法

/**
 *  1.调用运行时类的构造器
 *      - 私有构造器
 *  2.调用运行时类的方法
 *      - 成员方法
 *      - 静态方法
 *  3.调用运行时类的属性
 *      - 成员属性
 *      - 静态属性
 */
public class Test1 {
    //2.调用运行时类的方法
    @Test
    public void test2() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance("name");
        //成员方法
        Method play = clazz.getDeclaredMethod("play");
        play.setAccessible(true);
        play.invoke(o);
        //静态方法
        Method work = clazz.getDeclaredMethod("work");
        work.setAccessible(true);
        work.invoke(null);
        work.invoke(Person.class);
    }
}

6.3 属性

/**
 *  1.调用运行时类的构造器
 *      - 私有构造器
 *  2.调用运行时类的方法
 *      - 成员方法
 *      - 静态方法
 *  3.调用运行时类的属性
 *      - 成员属性
 *      - 静态属性
 */
public class Test1 {
    //1.调用运行时类的属性
    @Test
    public void test3() throws Exception {
        Class clazz = Class.forName("org.example.java.getStructure.Person");
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance("name");
        //成员属性
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(o,"lzw");
        //静态属性
        Field age = clazz.getDeclaredField("age");
        age.setAccessible(true);
        age.set(o,1);
        System.out.println(o);
    }
}

七、应用:动态代理

7.1 代理模式

  • 原理:

    使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

  • 静态代理

    • 之前为大家讲解过代理机制的操作,属于静态代理,特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能
  • 动态代理

    • 客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
    • 使用场合:
      • 调试
      • 远程方法调用

动态代理的优点:

抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

7.2 静态代理

/**
 *  静态代理
 *  特点:代理类和被代理类在编译期间,就确定下来了。
 */
public class StaticProxy {
    public static void main(String[] args) {
        NickCloth nickCloth=new NickCloth();
        ProxyNickCloth proxyNickCloth=new ProxyNickCloth(nickCloth);
        proxyNickCloth.produceCloth();
    }
}
interface ClothFactory{
    void produceCloth();
}
class NickCloth implements ClothFactory{
    @Override
    public void produceCloth() {
        System.out.println("生产耐克运动服");
    }
}
class ProxyNickCloth implements ClothFactory{
    private NickCloth nickCloth;
    ProxyNickCloth(NickCloth nickCloth){
        this.nickCloth=nickCloth;
    }
    @Override
    public void produceCloth() {
        System.out.println("代理进行生产准备");
        nickCloth.produceCloth();
        System.out.println("代理进行收尾处理");
    }
}

7.3 动态代理:AOP

注意:AOP思想

  • 根据需要创建不同的处理器
  • 使用多个处理生成的代理对象可以拥有所需要的不同功能。
/**
 * 动态代理
 * 要想实现动态代理,需要解决的问题?
 *      问题一:继承被代理类对象实现的接口生成代理类
 *      问题二:在代理类中的各个方法中调用被代理对象对应的方法
 */
public class DynamicProxy {
    public static void main(String[] args) {
        ShoeFactory nickShoe=new NickShoe();
        ShoeFactory proxy = (ShoeFactory) DynamicProxy.getProxy(nickShoe);
        proxy.processShoe();
        proxy.produceShoe();
    }
    public static Object getProxy(Object o){
        //解决问题二:在代理类中的各个方法中调用被代理对象对应的方法
        MyHandler handler=new MyHandler(o);
        //解决问题一:继承被代理类对象实现的接口生成代理类
        return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), handler);
    }
}
/**
 * 解决问题二:在代理类中的各个方法中调用被代理对象对应的方法
 *      - 1.保存被代理类对象
 *      - 2.调用被代理类对象的方法都会进入invoke方法
 *      - 3.在invoke方法中对被代理类对象的方法进行调用
 *      - 4.根据需要在invoke方法中增加其他业务功能
 */
class MyHandler implements InvocationHandler {
    Object o;
    public MyHandler(Object o){
        this.o=o;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理准备工作");
        Object invoke = method.invoke(o, args);
        System.out.println("代理收尾工作");
        return invoke;
    }
}




//接口:鞋子工厂
interface ShoeFactory{
    void processShoe();
    void produceShoe();
}
//实现类:鞋子工厂的被代理类
class NickShoe implements ShoeFactory{
    @Override
    public void processShoe() {
        System.out.println("加工鞋子");
    }
    @Override
    public void produceShoe() {
        System.out.println("生产鞋子");
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愿你满腹经纶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值