Java进阶学习之反射与动态绑定(5)

1.反射

1.1.概述

Java的反射机制是指在程序的运行状态时,可以构建任何一个类的对象,对任何一个对象可以了解其所属的成员变量和方法,这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。

1.2.实现方式

在最初的 helloworld案例 中,我们知道源代码会编译成字节码文件.class,然后交给JVM运行,这里的字节码文件其实就是类的模板,所有的对象都需要通过这个模板进行创建。所以在使用反射之前需要获取字节码文件。

1.2.1.获取Class

方式一:通过对象获取
方式二:通过 类.class 获取
方式三:通过Class类的静态方法forName(String className)获取
例子:
实体类:

public class Person {
    private String name;
    public Integer age;
    
    public Person() {}

    public Person(String name) {
        this.name = name;
    }
    
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String say(String name) {
        return "hello, " + name;
    }

    private String secretlySay(Integer time) {
        return "I love you " + time + " thousand times!";
    }
}

测试类:

public class TestReflection {
    public static void main(String[] args) {
        //方式一
        Person person = new Person("zhangsan", 22);
        Class clazz1 = person.getClass();
        System.out.println(clazz1);


        //方式一
        Class clazz2 = Person.class;
        System.out.println(clazz2);

        //方式三
        try {
            Class clazz3 = Class.forName("com.liquor.reflection.Person");
            System.out.println(clazz3);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

执行结果:
在这里插入图片描述
我们知道这里的Class对象其实就是类的模板,因此有且只有一个。

1.2.2.通过反射获取属性、设置属性

以下都是用第一种方式获取Class的。

public class TestReflection {
    public static void main(String[] args) {
        Person person = new Person("zhangsan", 22);
        Class clazz1 = person.getClass();
        System.out.println(clazz1);
        System.out.println("---------------------------");

        //获取public属性
        Field[] fields = clazz1.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("---------------------------");

        //获取包含private的所有属性
        Field[] declaredFields = clazz1.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field.getName());
        }

        try {
            //获取指定name的public属性
            Field age = clazz1.getField("age");
            System.out.println(age);
            //获取指定name的包含private的属性
            Field name = clazz1.getDeclaredField("name");
            System.out.println(name);

            //获取对象
            Object o = clazz1.newInstance();
            //设置属性不校验
            name.setAccessible(true);
            //设置属性值,私有属性需要关闭校验
            name.set(o, "lisi");
            age.set(o, 33);
            System.out.println(o);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

执行结果:
在这里插入图片描述

1.2.3.通过反射获取方法、执行方法
public class TestReflection {
    public static void main(String[] args) {
        Person person = new Person("zhangsan", 22);
        Class clazz1 = person.getClass();

        //获取类及其父类的public方法
        Method[] methods = clazz1.getMethods();
        for (Method method : methods) {
            System.out.print(method.getName() + " ");
        }
        System.out.println();

        //获取类包含private的所有方法
        Method[] methods2 = clazz1.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.print(method.getName() + " ");
        }
        System.out.println();

        try {
            //获取指定name的public方法
            Method m1 = clazz1.getMethod("say", String.class);
            System.out.println(m1);
            //获取指定name的包含private的方法
            Method m2 = clazz1.getDeclaredMethod("say", String.class);
            System.out.println(m2);
            Method m3 = clazz1.getDeclaredMethod("secretlySay", Integer.class);
            System.out.println(m3);

            //获取对象
            Object o = clazz1.newInstance();
            //设置方法不校验
            m3.setAccessible(true);
            //调用方法
            Object rel1 = m1.invoke(o, "lisi");
            System.out.println(rel1);
            Object rel2 = m3.invoke(o, 3);
            System.out.println(rel2);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

执行结果:
在这里插入图片描述

1.2.4.通过反射获取构造器并调用
public class TestReflection {
    public static void main(String[] args) {
        Person person = new Person("zhangsan", 22);
        Class clazz1 = person.getClass();

        //获取类的public构造器
        Constructor[] constructors = clazz1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("------------------------");

        try {
            //获取指定name的public构造器
            Constructor c1 = clazz1.getConstructor(String.class);
            System.out.println(c1);
            Constructor c2 = clazz1.getConstructor(String.class, Integer.class);
            System.out.println(c2);

            //通过构造器获取对象
            Object o1 = c1.newInstance("zhangsan");
            System.out.println(o1);
            Object o2 = c2.newInstance("lisi", 33);
            System.out.println(o2);

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}

执行结果:
在这里插入图片描述

2.动态代理

2.1.代理模式

使用一个类代表另一个类的功能,是一种设计模式。

2.2.静态代理

编译时代理类已经生成。
例子:
接口HelloService.java

public interface HelloService {
    String say(String name);
}

实际实现HelloServiceImpl

public class HelloServiceImpl implements HelloService {
    @Override
    public String say(String name) {
        return "Hello, " + name;
    }
}

代理类HelloStaticProxy.java

public class HelloStaticProxy implements HelloService {

    private HelloService helloService = new HelloServiceImpl();

    @Override
    public String say(String name) {
        System.out.println("--------------------------");
        return helloService.say(name);
    }
}

测试类:

public class TestProxy {
    public static void main(String[] args) {
        HelloStaticProxy helloStaticProxy = new HelloStaticProxy();
        System.out.println(helloStaticProxy.say("zhangsan"));
    }
}

执行结果:
在这里插入图片描述
静态代理实现步骤:

  1. 创建接口
  2. 实现接口
  3. 创建代理类实现接口并且将原实现类引入,调用实现的方法
    缺点:
  • 由于实现同一个接口,接口变动则修改成本增加
  • 如果接口实现方法很多的话再实现工作量很大

2.3.动态代理

相比静态代理,动态代理就是运行时动态创建代理的方式。
接口和被代理类与前面一样。
代理类:

public class HelloProxy implements InvocationHandler {

    private Object obj;

    public HelloProxy(Object obj) {
        this.obj = obj;
    }

    public Object getNewInstance() {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(obj, args);
        return invoke;
    }
}

测试类:

public class TestProxy {
    public static void main(String[] args) {
        HelloProxy helloProxy = new HelloProxy(new HelloServiceImpl());
        HelloService helloService = (HelloService) helloProxy.getNewInstance();
        System.out.println(helloService.say("zhangsan"));

    }
}

执行结果:
在这里插入图片描述
这是使用JDK源码实现的动态代理,使用接口等实现的。而如何被代理类没有实现接口呢?
被代理类HelloServiceClass.java

public class HelloServiceClass {
    public String say(String name) {
        return "Hello, " + name;
    }
}

代理类:

public class HelloProxy implements InvocationHandler {

    private Object obj;

    public HelloProxy(Object obj) {
        this.obj = obj;
    }

    public Object getNewInstance() {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(obj, args);
        return invoke;
    }
}

测试类:

public class TestProxy {
    public static void main(String[] args) {
        HelloServiceClass helloServiceClass = (HelloServiceClass) new CglibInterceptor().getNewInstance(HelloServiceClass.class);
        System.out.println(helloServiceClass.say("zhangsan"));
    }
}

执行结果:
在这里插入图片描述
静态代理相对于动态代理从代码的实现上更加容易理解和编写,代理类中调用的是真正的实现类。动态代理中,当我们需要使用到时才会创建类的模板然后创建对象调用方法。很显然反射在动态代理中举足轻重。

posted @ 2022-12-01 10:42  liquorppp  阅读(30)  评论(0编辑  收藏  举报