动态语言
动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化。比如常见的 JavaScript 就是动态语言,除此之外 Ruby,Python 等也属于动态语言,而 C、C++则不属于动态语言。从反射角度说 JAVA 属于半动态语言。
反射机制--运行中知道全部的类和属性
在 Java 中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制。
反射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新增基本类型的属性:
注释掉全部的setter、getter方法
重写toString方法
接着使用反射设置属性:基本属性需要使用对应的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);
}
}
结果:
Method
新增不同权限的方法:
接下来使用反射执行这些方法
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有两个构造方法
接着使用反射试试
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
反射步骤
- 获取Class对象
- 获取Class方法或者属性
- 执行Class方法或者属性赋值
获取Class
==getClass()==
Object object = new Object();
Class clazz = object.getClass();
==class关键字==
Class clazz = Object.class;
==forName()==
Class clazz = Class.forName("com.xxxxxx");