Java 聊聊反射机制和动态代理

1.反射

反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息,并且可以执行其方法。适用于程序在运行期,对某个实例一无所知的情况下,如何调用其方法。反射引入的类不需要使用 import 关键字进行导入。

1.1优点

因为是动态编译,所以灵活度高,运行时动态加载。

1.2缺点

  • 执行效率低。因为反射机制都是 JVM 实现的。
  • 破坏了三大特性中的继承的特性。

2. Class 类

除基本数据类型(int,float....)之外,Java的其他类型全部都是class(包括interface)。而class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来。注意:这里的Class类型是一个名叫Classclass。创建的Class中包含了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等。

2.1创建Class

//方法1
Class cls = String.class;

//方法2
String s = "Hello";
Class cls = s.getClass();

//方法3
Class cls = Class.forName("java.lang.String");

2.2利用反射创建对象

//正常方式创建对象
String str1 = new String();
//反射创建对象
Class cls = String.class;
String str2 = (String)cls.newInstance();

通过Class.newInstance()可以创建类实例,它的局限是:只能调用public的无参数构造方法。带参数的构造方法,或者非public的构造方法都无法通过Class.newInstance()被调用。

2.3动态加载

Java所有的类都是动态加载的,也可以说懒加载。即用到时候在加载,不用的话就不会加载。动态加载class的特性对于Java程序非常重要。

3.使用大纲

Java 聊聊反射机制和动态代理_第1张图片

3.1访问字段

获取其Class就意味着获取了该类的所有信息,我们可以使用以下四种方法来获取字段的值。

Java 聊聊反射机制和动态代理_第2张图片

示例:

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Main {
    public static void main(String[] args) throws Exception {
        Class studentClass = Student.class;
        //Field getField(name):根据字段名获取某个public的field(包括父类)
        System.out.println("=====getField=====");
        System.out.println(studentClass.getField("age"));
        //Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
        System.out.println("=====getDeclaredField=====");
        System.out.println(studentClass.getDeclaredField("classNo"));
        //Field[] getFields():获取所有public的field(包括父类)
        System.out.println("=====getFields=====");
        Field[] Fields1 = studentClass.getFields();
        for (Field f :Fields1) {
            System.out.println(f);
        }
        //Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
        System.out.println("=====getDeclaredFields=====");
        Field[] Fields2 = studentClass.getDeclaredFields();
        for (Field f :Fields2) {
            System.out.println(f);
        }
        //获取字段信息
        System.out.println("=====获取字段信息=====");
        Field age = studentClass.getField("age");
        System.out.println(age.getName());
        System.out.println(age.getType());
        int m = age.getModifiers();
        System.out.println(Modifier.isFinal(m));

        System.out.println(Modifier.isPublic(m));
        System.out.println(Modifier.isProtected(m));
        System.out.println(Modifier.isPrivate(m));
        System.out.println(Modifier.isStatic(m));
        //获取字段值
        System.out.println("=====获取字段值=====");
        Student stu = new Student();
        stu.stuNo = "20200202";
        Class stuClass = stu.getClass();
        Field stuNo = stuClass.getDeclaredField("stuNo");
        stuNo.setAccessible(true);
        Object value = stuNo.get(stu);
        System.out.println(value);
        //设置字段值
        System.out.println("=====设置字段值=====");
        stuNo.set(stu,"02022020");
        value = stuNo.get(stu);
        System.out.println(value);
    }
}
class Person{
    private String name;
    public int age;
}

class Student extends Person{
    public String stuNo;
    private String classNo;
}

结果:

=====getField=====
public int Person.age
=====getDeclaredField=====
private java.lang.String Student.classNo
=====getFields=====
public java.lang.String Student.stuNo
public int Person.age
=====getDeclaredFields=====
public java.lang.String Student.stuNo
private java.lang.String Student.classNo
=====获取字段信息=====
age
int
false
true
false
false
false
=====获取字段值=====
20200202
=====设置字段值=====
02022020

3.2调用方法

Java 聊聊反射机制和动态代理_第3张图片

示例:

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        Class stuClass = Student.class;
        //Method getMethod(name, Class...):获取某个public的Method(包括父类)
        System.out.println("=====getMethod=====");
        Method personPrint = stuClass.getMethod("personPrint", String.class);
        System.out.println(personPrint);
        //Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
        System.out.println("=====getDeclaredMethod=====");
        Method studentPrint = stuClass.getMethod("studentPrint", String.class);
        System.out.println(studentPrint);
        //Method[] getMethods():获取所有public的Method(包括父类)
        System.out.println("=====getMethods=====");
        Method[] methods = stuClass.getMethods();
        for(Method m : methods){
            System.out.println(m);
        }
        //Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
        System.out.println("=====getMethods=====");
        Method[] methods1 = stuClass.getDeclaredMethods();
        for(Method m : methods1){
            System.out.println(m);
        }
        //获取Method对象信息
        System.out.println("=====获取对象信息=====");
        System.out.println(studentPrint.getName());
        System.out.println(studentPrint.getReturnType());
        Class[] parameterTypes = studentPrint.getParameterTypes();
        for (Class c:parameterTypes) {
            System.out.println(c);
        }
        System.out.println(studentPrint.getModifiers());
        //调用方法
        System.out.println("=====调用方法=====");
        Student s = new Student();
        Method studentPrintMethod = Student.class.getDeclaredMethod("studentPrint", String.class);
        Object abc = studentPrintMethod.invoke(s, "abc");
        System.out.println(abc);
    }
}
class Person{
    public String getName(){
        return "Person";
    }
    public String personPrint(String val){
        return val;
    }
}

class Student extends Person{
    public String stuNo(){
        return "20200202";
    }
    private int getAge(){
        return 20;
    }
    public String studentPrint(String val){
        return val;
    }
}

结果:

=====getMethod=====
public java.lang.String Person.personPrint(java.lang.String)
=====getDeclaredMethod=====
public java.lang.String Student.studentPrint(java.lang.String)
=====getMethods=====
public java.lang.String Student.studentPrint(java.lang.String)
public java.lang.String Student.stuNo()
public java.lang.String Person.getName()
public java.lang.String Person.personPrint(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
=====getMethods=====
public java.lang.String Student.studentPrint(java.lang.String)
private int Student.getAge()
public java.lang.String Student.stuNo()
=====获取对象信息=====
studentPrint
class java.lang.String
class java.lang.String
1
=====调用方法=====
abc

3.3调用构造方法

Java 聊聊反射机制和动态代理_第4张图片

注意:

  1. 注意Constructor总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。
  2. 调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。

示例:

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) throws Exception {
        //newInstance 方法调用构造方法
        //它只能调用该类的public无参数构造方法。如果构造方法带有参数,
        //或者不是public,就无法直接通过Class.newInstance()来调用。
        Person person = Person.class.newInstance();
        //getConstructor(Class...):获取某个public的Constructor
        Class perClass = Person.class;
        System.out.println("=====getConstructor=====");
        Constructor perClassConstructor = perClass.getConstructor();
        Person p1 = (Person)perClassConstructor.newInstance();
        System.out.println(p1);
        //getDeclaredConstructor(Class...):获取某个Constructor
        System.out.println("=====getDeclaredConstructor=====");
        Constructor declaredConstructor = perClass.getDeclaredConstructor(Integer.class);
        Person p2 = (Person)declaredConstructor.newInstance(12);
        System.out.println(p2);
        //getConstructors():获取所有public的Constructor
        System.out.println("=====getConstructors=====");
        Constructor[] constructors = perClass.getConstructors();
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }
        //getDeclaredConstructors():获取所有Constructor
        System.out.println("=====getDeclaredConstructors=====");
        Constructor[] constructors1 = perClass.getDeclaredConstructors();
        for (Constructor constructor : constructors1){
            System.out.println(constructor);
        }
    }
}
class Person{
    public Person() {
        System.out.println("Person ....");
    }
    private Person(String name) {
        System.out.println("Person name ....");
    }
    public Person(Integer age) {
        System.out.println("Person age ....");
    }
}

结果:

Person ....
=====getConstructor=====
Person ....
Person@1540e19d
=====getDeclaredConstructor=====
Person age ....
Person@677327b6
=====getConstructors=====
public Person()
public Person(java.lang.Integer)
=====getDeclaredConstructors=====
public Person()
private Person(java.lang.String)
public Person(java.lang.Integer)

3.4获取继承关系

Java 聊聊反射机制和动态代理_第5张图片

示例:

import java.io.Serializable;

public class Main {
    public static void main(String[] args) throws Exception {
        Class studentClass = Student.class;
        //getSuperclass():获取它的父类的Class
        System.out.println("=====getSuperclass=====");
        Class superclass = studentClass.getSuperclass();
        System.out.println(studentClass);
        //getInterfaces():获取当前类实现的所有接口数组Class[]
        System.out.println("=====getInterfaces=====");
        Class[] interfaces = studentClass.getInterfaces();
        for(Class c : interfaces){
            System.out.println(c);
        }
        //isAssignableFrom():判断一个向上转型是否可以实现
        System.out.println("=====isAssignableFrom=====");
        System.out.println(Person.class.isAssignableFrom(Student.class));
        System.out.println(Person.class.isAssignableFrom(Person.class));
        System.out.println(Object.class.isAssignableFrom(Person.class));
    }
}
class Person{

}
interface Study{

}
class Student extends Person implements Study,Serializable{

}

结果:

=====getSuperclass=====
class Student
=====getInterfaces=====
interface Study
interface java.io.Serializable
=====isAssignableFrom=====
true
true
true

4.动态代理

代理:为其它对象提供一种代理以控制对这个对象的访问控制;在某些情况下,客户不想或者不能直接引用另一个对象,这时候代理对象可以在客户端和目标对象之间起到中介的作用。

代理分为两种:静态代理和动态代理

4.1静态代理

创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。

示例:

public class Main {
    public static void main(String[] args) throws Exception {
        Student stu = new Student("语文");
        PersonProxy pp = new PersonProxy();
        pp.setStu(stu);
        pp.learn();
    }
}
class PersonProxy implements Study{
    private Student stu = null;

    public void setStu(Student stu) {
        this.stu = stu;
    }

    public Student getStu() {
        return stu;
    }

    @Override
    public void learn() {
        if(stu != null){
            System.out.println("invoked proxy learn before");
            stu.learn();
            System.out.println("invoked proxy learn after");
        }
    }
}
interface Study{
    void learn();
}
class Student implements Study{

    private String book = null;

    public Student(String book) {
        this.book = book;
    }

    @Override
    public void learn() {
        System.out.println("learning...."+book);
    }
}

结果:

invoked proxy learn before
learning....语文
invoked proxy learn after

优点:清晰明了,实现简单

缺点:一个类代理一个对象,如果需要代理很多类,就要编写大量的代理类。

4.2动态代理 

可以不用实现接口,直接使用代理对象。

示例:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) throws Exception {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if(method.getName().equals("learn")){
                    System.out.println("learning...."+args[0]);
                }
                return null;
            }
        };
        Study study = (Study) Proxy.newProxyInstance(
                Study.class.getClassLoader(),//传入ClassLoader
                new Class[]{Study.class},//传入要实现的接口
                handler);// 传入处理调用方法的InvocationHandler
        study.learn("语文");
    }
}
interface Study{
    void learn(String book);
}
// 要实现的代理对象
class Student implements Study{
    @Override
    public void learn(String book) {
        System.out.println("learning...."+book);
    }
}

结果:

public abstract void Study.learn(java.lang.String)
learning....语文

 

你可能感兴趣的:(Java)