Java--反射详解

动态语言

动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化。比如常见的 JavaScript 就是动态语言,除此之外 Ruby,Python 等也属于动态语言,而 C、C++则不属于动态语言。从反射角度说 JAVA 属于半动态语言。

反射机制--运行中知道全部的类和属性

在 Java 中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制。

image-20200813182038074

反射API

反射API用来生成JVM中的类、接口或者对象的信息。

  • Class类:反射的核心类,可以获取类的属性,方法等信息。
  • Field类:表示类的成员变量,可以用来获取和设置类中的属性值。
  • Method类:表示类的方法,可以用来类中的方法信息,或者执行方法。
  • Constructor类:表示类的构造方法。

Class

准备一个类

import java.io.Serializable;
@Deprecated
public class People implements Serializable {

    private String name;

    private Integer age;

    private String testPrivate;

    public String testPublic;

    protected String testProtected;

    String testDefault;

    public People(){

    }

    public String say(){
        return name+age;
    }


    public String getName() {
        return this.name;
    }

    public Integer getAge() {
        return this.age;
    }

    public String getTestPrivate() {
        return this.testPrivate;
    }

    public String getTestPublic() {
        return this.testPublic;
    }

    public String getTestProtected() {
        return this.testProtected;
    }

    public String getTestDefault() {
        return this.testDefault;
    }

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

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

    public void setTestPrivate(String testPrivate) {
        this.testPrivate = testPrivate;
    }

    public void setTestPublic(String testPublic) {
        this.testPublic = testPublic;
    }

    public void setTestProtected(String testProtected) {
        this.testProtected = testProtected;
    }

    public void setTestDefault(String testDefault) {
        this.testDefault = testDefault;
    }
}

接下来获取这个类的属性和方法等信息

import com.study.studyreflect.bean.People;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ClassMain {

    public static void main(String[] args) throws ClassNotFoundException {
        Class clazz1 = People.class;
        People people = new People();
        Class clazz2 = people.getClass();
        Class clazz3 = Class.forName("com.study.studyreflect.bean.People");
        System.out.println(clazz1);
        System.out.println(clazz2);
        System.out.println(clazz3);
        Method[] methods = clazz1.getMethods();
        System.out.println("--------------------class----------------------------");
        Arrays.asList(methods).stream().forEach(x->
                System.out.println("class: " + x.getClass()+",name: " + x.getName() + ",parameter: " + x.getParameters().toString()+",returnType: " + x.getReturnType()));
        System.out.println("--------------------public field----------------------------");
        Field[] fields = clazz1.getFields();
        Arrays.asList(fields).stream().forEach(x->
                System.out.println("class: " + x.getClass() + ",name: " + x.getName() + ",type: " + x.getType()));
        System.out.println("--------------------all field----------------------------");
        Field[] declaredFields = clazz1.getDeclaredFields();
        Arrays.asList(declaredFields).stream().forEach(x->
                System.out.println("class: " + x.getClass() + ",name: " + x.getName() + ",type: " + x.getType() + ",getDeclaringClass: " + x.getDeclaringClass()));
        System.out.println("--------------------annotations----------------------------");
        Annotation[] annotations = clazz1.getAnnotations();
        Arrays.asList(annotations).stream().forEach(x->
                System.out.println("class: " + x.getClass() + ",type: " + x.annotationType()));
        System.out.println("--------------------interface----------------------------");
        Class[] interfaces = clazz1.getInterfaces();
        Arrays.asList(interfaces).stream().forEach(x->
                System.out.println("class: " + x.getClass() + ",name: " + x.getName() + ",typeName: " + x.getTypeName()));
    }

}

输出

F:\JDK\jdk\jdk8u111\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=60825:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath F:\JDK\jdk\jdk8u111\jre\lib\charsets.jar;F:\JDK\jdk\jdk8u111\jre\lib\deploy.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\access-bridge-64.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\cldrdata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\dnsns.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jaccess.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jfxrt.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\localedata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\nashorn.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunec.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunjce_provider.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunmscapi.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunpkcs11.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\zipfs.jar;F:\JDK\jdk\jdk8u111\jre\lib\javaws.jar;F:\JDK\jdk\jdk8u111\jre\lib\jce.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfr.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfxswt.jar;F:\JDK\jdk\jdk8u111\jre\lib\jsse.jar;F:\JDK\jdk\jdk8u111\jre\lib\management-agent.jar;F:\JDK\jdk\jdk8u111\jre\lib\plugin.jar;F:\JDK\jdk\jdk8u111\jre\lib\resources.jar;F:\JDK\jdk\jdk8u111\jre\lib\rt.jar;G:\studyjdk\out\production\studyreflect com.study.studyreflect.ClassMain
class com.study.studyreflect.bean.People
class com.study.studyreflect.bean.People
class com.study.studyreflect.bean.People
--------------------class----------------------------
class: class java.lang.reflect.Method,name: getName,parameter: [Ljava.lang.reflect.Parameter;@214c265e,returnType: class java.lang.String
class: class java.lang.reflect.Method,name: setName,parameter: [Ljava.lang.reflect.Parameter;@448139f0,returnType: void
class: class java.lang.reflect.Method,name: getAge,parameter: [Ljava.lang.reflect.Parameter;@7cca494b,returnType: class java.lang.Integer
class: class java.lang.reflect.Method,name: say,parameter: [Ljava.lang.reflect.Parameter;@7ba4f24f,returnType: class java.lang.String
class: class java.lang.reflect.Method,name: getTestPublic,parameter: [Ljava.lang.reflect.Parameter;@3b9a45b3,returnType: class java.lang.String
class: class java.lang.reflect.Method,name: setAge,parameter: [Ljava.lang.reflect.Parameter;@7699a589,returnType: void
class: class java.lang.reflect.Method,name: setTestPublic,parameter: [Ljava.lang.reflect.Parameter;@58372a00,returnType: void
class: class java.lang.reflect.Method,name: getTestPrivate,parameter: [Ljava.lang.reflect.Parameter;@4dd8dc3,returnType: class java.lang.String
class: class java.lang.reflect.Method,name: setTestDefault,parameter: [Ljava.lang.reflect.Parameter;@6d03e736,returnType: void
class: class java.lang.reflect.Method,name: setTestProtected,parameter: [Ljava.lang.reflect.Parameter;@568db2f2,returnType: void
class: class java.lang.reflect.Method,name: getTestProtected,parameter: [Ljava.lang.reflect.Parameter;@378bf509,returnType: class java.lang.String
class: class java.lang.reflect.Method,name: getTestDefault,parameter: [Ljava.lang.reflect.Parameter;@5fd0d5ae,returnType: class java.lang.String
class: class java.lang.reflect.Method,name: setTestPrivate,parameter: [Ljava.lang.reflect.Parameter;@2d98a335,returnType: void
class: class java.lang.reflect.Method,name: wait,parameter: [Ljava.lang.reflect.Parameter;@16b98e56,returnType: void
class: class java.lang.reflect.Method,name: wait,parameter: [Ljava.lang.reflect.Parameter;@7ef20235,returnType: void
class: class java.lang.reflect.Method,name: wait,parameter: [Ljava.lang.reflect.Parameter;@27d6c5e0,returnType: void
class: class java.lang.reflect.Method,name: equals,parameter: [Ljava.lang.reflect.Parameter;@4f3f5b24,returnType: boolean
class: class java.lang.reflect.Method,name: toString,parameter: [Ljava.lang.reflect.Parameter;@15aeb7ab,returnType: class java.lang.String
class: class java.lang.reflect.Method,name: hashCode,parameter: [Ljava.lang.reflect.Parameter;@7b23ec81,returnType: int
class: class java.lang.reflect.Method,name: getClass,parameter: [Ljava.lang.reflect.Parameter;@6acbcfc0,returnType: class java.lang.Class
class: class java.lang.reflect.Method,name: notify,parameter: [Ljava.lang.reflect.Parameter;@5f184fc6,returnType: void
class: class java.lang.reflect.Method,name: notifyAll,parameter: [Ljava.lang.reflect.Parameter;@3feba861,returnType: void
--------------------public field----------------------------
class: class java.lang.reflect.Field,name: testPublic,type: class java.lang.String
--------------------all field----------------------------
class: class java.lang.reflect.Field,name: name,type: class java.lang.String,getDeclaringClass: class com.study.studyreflect.bean.People
class: class java.lang.reflect.Field,name: age,type: class java.lang.Integer,getDeclaringClass: class com.study.studyreflect.bean.People
class: class java.lang.reflect.Field,name: testPrivate,type: class java.lang.String,getDeclaringClass: class com.study.studyreflect.bean.People
class: class java.lang.reflect.Field,name: testPublic,type: class java.lang.String,getDeclaringClass: class com.study.studyreflect.bean.People
class: class java.lang.reflect.Field,name: testProtected,type: class java.lang.String,getDeclaringClass: class com.study.studyreflect.bean.People
class: class java.lang.reflect.Field,name: testDefault,type: class java.lang.String,getDeclaringClass: class com.study.studyreflect.bean.People
--------------------annotations----------------------------
class: class com.sun.proxy.$Proxy1,type: interface java.lang.Deprecated
--------------------interface----------------------------
class: class java.lang.Class,name: java.io.Serializable,typeName: java.io.Serializable

Process finished with exit code 0

Field

还是使用People作为目标类,尝试用反射设置属性。

People新增基本类型的属性:

image-20200813193135758

注释掉全部的setter、getter方法

image-20200813193216175

重写toString方法

image-20200813193234214

接着使用反射设置属性:基本属性需要使用对应的setXXX方法

public class FieldMain {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        People people = new People();
        Class clazz = Class.forName("com.study.studyreflect.bean.People");
        System.out.println("------------setName----------------");
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(people, "小美");
        System.out.println("------------setAge-----------------");
        Field age = clazz.getDeclaredField("age");
        age.setAccessible(true);
        age.set(people, 22);
        System.out.println("------------setNumber-----------------");
        Field number = clazz.getDeclaredField("number");
        number.setAccessible(true);
        number.setInt(people, 88);
        System.out.println("------------testPublic-----------------");
        Field testPublic = clazz.getDeclaredField("testPublic");
        testPublic.setAccessible(true);
        testPublic.set(people,"test##public");
        System.out.println("------------testprivate-----------------");
        Field testPrivate = clazz.getDeclaredField("testPrivate");
        testPrivate.setAccessible(true);
        testPrivate.set(people,"test##private");
        System.out.println("------------testProtected-----------------");
        Field testProtected = clazz.getDeclaredField("testProtected");
        testProtected.setAccessible(true);
        testProtected.set(people, "test##protected");
        System.out.println("------------testDefault-----------------");
        Field testDefault = clazz.getDeclaredField("testDefault");
        testDefault.setAccessible(true);
        testDefault.set(people, "test##Default");
        System.out.println(people);
    }

}

输出结果

F:\JDK\jdk\jdk8u111\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=62716:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath F:\JDK\jdk\jdk8u111\jre\lib\charsets.jar;F:\JDK\jdk\jdk8u111\jre\lib\deploy.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\access-bridge-64.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\cldrdata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\dnsns.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jaccess.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jfxrt.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\localedata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\nashorn.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunec.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunjce_provider.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunmscapi.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunpkcs11.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\zipfs.jar;F:\JDK\jdk\jdk8u111\jre\lib\javaws.jar;F:\JDK\jdk\jdk8u111\jre\lib\jce.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfr.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfxswt.jar;F:\JDK\jdk\jdk8u111\jre\lib\jsse.jar;F:\JDK\jdk\jdk8u111\jre\lib\management-agent.jar;F:\JDK\jdk\jdk8u111\jre\lib\plugin.jar;F:\JDK\jdk\jdk8u111\jre\lib\resources.jar;F:\JDK\jdk\jdk8u111\jre\lib\rt.jar;G:\studyjdk\out\production\studyreflect com.study.studyreflect.FieldMain
------------setName----------------
------------setAge-----------------
------------setNumber-----------------
------------testPublic-----------------
------------testprivate-----------------
------------testProtected-----------------
------------testDefault-----------------
People[name=小美,age=22,number=88,testPublic=test##public,testPrivate=test##private,testProtected=test##protected,testDefault=test##Default]

Process finished with exit code 0

这反射就是个bug,完全不理会权限...

小例子,使用反射,创建20个实例,名字+id

public class FieldMain {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        Class clazz = Class.forName("com.study.studyreflect.bean.People");
        int summer = 10;
        Object[] objects = new Object[summer];
        for (int i = 0; i < summer; i++) {
            Object instance = clazz.newInstance();
            Field name = clazz.getDeclaredField("name");
            name.setAccessible(true);
            name.set(instance, "小美"+i);
            objects[i] = instance;
        }
        Arrays.asList(objects).stream().forEach(System.out::println);
    }

}

结果:

image-20200813194057725

Method

新增不同权限的方法:

image-20200813194145511

接下来使用反射执行这些方法

import com.study.studyreflect.bean.People;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodMain {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class clazz = Class.forName("com.study.studyreflect.bean.People");
        People people = (People) clazz.newInstance();
        people.setName("小美");
        people.setAge(24);
        people.setNumber(78);
        System.out.println("-------------------public------------");
        Method sayPublic = clazz.getDeclaredMethod("say", null);
        sayPublic.setAccessible(true);
        System.out.println("public: " + sayPublic.invoke(people, null));
        System.out.println("-------------------private------------");
        Method sayPrivate = clazz.getDeclaredMethod("say", String.class);
        sayPrivate.setAccessible(true);
        System.out.println("private: " + sayPrivate.invoke(people, "小美:private"));
        System.out.println("-------------------protected------------");
        Method sayProtected = clazz.getDeclaredMethod("say", Integer.class);
        sayProtected.setAccessible(true);
        System.out.println("protected: " + sayProtected.invoke(people, 244));
        System.out.println("-------------------default------------");
        Method sayDefault = clazz.getDeclaredMethod("say", Double.class);
        sayDefault.setAccessible(true);
        System.out.println("default: " + sayDefault.invoke(people, 24.444));
        System.out.println("-------------------toString------------");
        Method toString = clazz.getDeclaredMethod("toString", null);
        toString.setAccessible(true);
        System.out.println("toString: " + toString.invoke(people, null));
    }

}

执行结果

F:\JDK\jdk\jdk8u111\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=64218:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath F:\JDK\jdk\jdk8u111\jre\lib\charsets.jar;F:\JDK\jdk\jdk8u111\jre\lib\deploy.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\access-bridge-64.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\cldrdata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\dnsns.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jaccess.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jfxrt.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\localedata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\nashorn.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunec.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunjce_provider.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunmscapi.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunpkcs11.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\zipfs.jar;F:\JDK\jdk\jdk8u111\jre\lib\javaws.jar;F:\JDK\jdk\jdk8u111\jre\lib\jce.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfr.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfxswt.jar;F:\JDK\jdk\jdk8u111\jre\lib\jsse.jar;F:\JDK\jdk\jdk8u111\jre\lib\management-agent.jar;F:\JDK\jdk\jdk8u111\jre\lib\plugin.jar;F:\JDK\jdk\jdk8u111\jre\lib\resources.jar;F:\JDK\jdk\jdk8u111\jre\lib\rt.jar;G:\studyjdk\out\production\studyreflect com.study.studyreflect.MethodMain
-------------------public------------
public: 小美24
-------------------private------------
private: 小美:private
-------------------protected------------
protected: 244
-------------------default------------
default: 24.444
-------------------toString------------
toString: People[name=小美,age=24,number=78,testPublic=null,testPrivate=null,testProtected=null,testDefault=null]

Process finished with exit code 0

果真是个bug....

==这里一定程度上能够体现:为什么java重载方法,不能根据权限和返回值区分,因为在反射中,相同名字的方法的唯一区分方式就是参数类型或者参数个数。==

==所以,重载方法,一定是参数不同。==

Constructor

People有两个构造方法

image-20200813200246028

接着使用反射试试

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ConstructorMain {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class clazz = Class.forName("com.study.studyreflect.bean.People");
        Constructor defaultCon = clazz.getDeclaredConstructor(null);
        defaultCon.setAccessible(true);
        Object defaultInstance = defaultCon.newInstance(null);
        System.out.println(defaultInstance);
        Constructor stringCon = clazz.getDeclaredConstructor(String.class);
        stringCon.setAccessible(true);
        Object xiao = stringCon.newInstance("小丽");
        System.out.println(xiao);
    }

}

执行结果

F:\JDK\jdk\jdk8u111\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=64841:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath F:\JDK\jdk\jdk8u111\jre\lib\charsets.jar;F:\JDK\jdk\jdk8u111\jre\lib\deploy.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\access-bridge-64.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\cldrdata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\dnsns.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jaccess.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\jfxrt.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\localedata.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\nashorn.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunec.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunjce_provider.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunmscapi.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\sunpkcs11.jar;F:\JDK\jdk\jdk8u111\jre\lib\ext\zipfs.jar;F:\JDK\jdk\jdk8u111\jre\lib\javaws.jar;F:\JDK\jdk\jdk8u111\jre\lib\jce.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfr.jar;F:\JDK\jdk\jdk8u111\jre\lib\jfxswt.jar;F:\JDK\jdk\jdk8u111\jre\lib\jsse.jar;F:\JDK\jdk\jdk8u111\jre\lib\management-agent.jar;F:\JDK\jdk\jdk8u111\jre\lib\plugin.jar;F:\JDK\jdk\jdk8u111\jre\lib\resources.jar;F:\JDK\jdk\jdk8u111\jre\lib\rt.jar;G:\studyjdk\out\production\studyreflect com.study.studyreflect.ConstructorMain
People[name=null,age=null,number=0,testPublic=null,testPrivate=null,testProtected=null,testDefault=null]
People[name=小丽,age=null,number=0,testPublic=null,testPrivate=null,testProtected=null,testDefault=null]

Process finished with exit code 0

反射步骤

  1. 获取Class对象
  2. 获取Class方法或者属性
  3. 执行Class方法或者属性赋值

获取Class

==getClass()==

Object object = new Object();
Class clazz = object.getClass();

==class关键字==

Class clazz = Object.class;

==forName()==

Class clazz = Class.forName("com.xxxxxx");

获取实例对象

==Class的newInstance()==

image-20200813201321220

==Constructor的newInstance()==

image-20200813201418144

你可能感兴趣的:(Java--反射详解)