反射 就是把Java类中的各个成分映射成一个个的Java对象。
即在运行状态中,对于任意一个类,都能够知道它的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。
最常见的场景就是访问某个类的私有属性、私有方法。
新建一个类 Avenger ,关注它的 私有属性、私有构造方法、私有方法。
package com.lah.reflect;
public class Avenger {
//私有属性
private static final String TAG = "TAG_Avenger";
private int id;
private String name;
public Avenger(){
}
//私有构造函数
private Avenger(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//私有方法
private String answersQuestion(int question){
String text = "nothing";
switch (question){
case 0:text = "Your question is 0";
case 1:text = "Your question is 1";
case 2:text = "Your question is 2";
default:break;
}
return text;
}
//私有方法
private String talkToSomeone(int id1, int id2, String msg){
System.out.println("Talk msg(" + msg + ") to " + id1 + " and " + id2);
return "talk well";
}
@Override
public String toString() {
return "Avenger{id=" + id +",name="+ name+"}";
}
}
正常调用,通过公有方法新建 Avenger 类。
public class TestReflect {
public static void main(String[] args) {
Avenger avenger = new Avenger();
avenger.setId(100);
avenger.setName("Avenger100");
System.out.println(avenger.toString());
}
}
运行结果,
Avenger{id=100,name=Avenger100}
一切正常。
public class TestReflect {
public static void main(String[] args) {
Avenger avenger = new Avenger();
avenger.setId(100);
avenger.setName("Avenger100");
System.out.println(avenger.toString());
reflectNewInstance();
}
// 创建对象
public static void reflectNewInstance() {
try {
Class> classAvenger= Class.forName("com.lah.reflect.Avenger");//注释1
Object objectBook = classAvenger.newInstance();
Avenger avenger1 = (Avenger) objectBook;
avenger1.setId(1);
avenger1.setName("Avenger1");
System.out.println(avenger1.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
运行结果,
Avenger{id=100,name=Avenger100}
Avenger{id=1,name=Avenger1}
说明反射成功了。
需要注意的是,如 注释1 处,反射时要传入完整的包名类名。
通过反射,可以获取到类的所有属性和方法,
package com.lah.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) {
Avenger avenger = new Avenger();
avenger.setId(100);
avenger.setName("Avenger100");
System.out.println(avenger.toString());
reflectAllProperty();
}
//反射获取所有属性和方法
public static void reflectAllProperty() {
try {
Field[] fields = Avenger.class.getDeclaredFields();
System.out.println(Avenger.class.getName() + "有如下属性:");
for (Field f : fields){
System.out.println(f);
}
System.out.println("\n");
Method[] methods = Avenger.class.getDeclaredMethods();
System.out.println(Avenger.class.getName() + "有如下方法:");
for (Method m: methods){
System.out.println(m);
}
} catch (SecurityException e) {
}
}
}
运行结果,
Avenger{id=100,name=Avenger100}
com.lah.reflect.Avenger有如下属性:
private static final java.lang.String com.lah.reflect.Avenger.TAG
private int com.lah.reflect.Avenger.id
private java.lang.String com.lah.reflect.Avenger.name
com.lah.reflect.Avenger有如下方法:
public java.lang.String com.lah.reflect.Avenger.toString()
public java.lang.String com.lah.reflect.Avenger.getName()
public int com.lah.reflect.Avenger.getId()
public void com.lah.reflect.Avenger.setName(java.lang.String)
private java.lang.String com.lah.reflect.Avenger.answersQuestion(int)
private java.lang.String com.lah.reflect.Avenger.talkToSomeone(int,int,java.lang.String)
public void com.lah.reflect.Avenger.setId(int)
Avenger 类中如下构造函数是私有的,无法直接调用。
//私有构造函数
private Avenger(int id, String name) {
this.id = id;
this.name = name;
}
用反射,
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) {
Avenger avenger = new Avenger();
avenger.setId(100);
avenger.setName("Avenger100");
System.out.println(avenger.toString());
reflectPrivateConstructor();
}
// 反射私有的构造方法
public static void reflectPrivateConstructor() {
try {
Class> classAvenger = Class.forName("com.lah.reflect.Avenger");
Constructor> declaredConstructorAvenger = classAvenger.getDeclaredConstructor(int.class, String.class);//注释2
declaredConstructorAvenger.setAccessible(true);//注释3
Object objectBook = declaredConstructorAvenger.newInstance(2,"Avenger2");
Avenger avenger2 = (Avenger) objectBook;
System.out.println(avenger2.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
注释2 处,类的构造方法传入的两个参数分别是 int 、String 类型,所以要这样写。
注释3 处,这样就破坏了私有属性。
运行结果,
Avenger{id=100,name=Avenger100}
Avenger{id=2,name=Avenger2}
在 Avenger 类中,TAG 属性是私有的,
private static final String TAG = "TAG_Avenger";
反射拿到,
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) {
Avenger avenger = new Avenger();
avenger.setId(100);
avenger.setName("Avenger100");
System.out.println(avenger.toString());
reflectPrivateField();
}
// 反射私有属性
public static void reflectPrivateField() {
try {
Class> classAvenger = Class.forName("com.lah.reflect.Avenger");
Object objectBook = classAvenger.newInstance();
Field fieldTag = classAvenger.getDeclaredField("TAG");
fieldTag.setAccessible(true);
String tag = (String) fieldTag.get(objectBook);
System.out.println(tag);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
运行结果,
Avenger{id=100,name=Avenger100}
TAG_Avenger
在 Avenger 类中,如下方法是私有的,
private String answersQuestion(int question){
String text = "nothing";
switch (question){
case 0:text = "Your question is 0";
case 1:text = "Your question is 1";
case 2:text = "Your question is 2";
default:break;
}
return text;
}
private String talkToSomeone(int id1, int id2, String msg){
System.out.println("Talk msg(" + msg + ") to " + id1 + " and " + id2);
return "talk well";
}
反射调用,
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) {
Avenger avenger = new Avenger();
avenger.setId(100);
avenger.setName("Avenger100");
System.out.println(avenger.toString());
reflectPrivateMethod();
reflectPrivateMethod2();
}
// 反射私有方法
public static void reflectPrivateMethod() {
try {
Class> classAvenger = Class.forName("com.lah.reflect.Avenger");
Method methodBook = classAvenger.getDeclaredMethod("answersQuestion",int.class);//注释4
methodBook.setAccessible(true);
Object object = classAvenger.newInstance();
String string = (String) methodBook.invoke(object,1);//注释5
System.out.println("reflectPrivateMethod, string:" + string);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射私有方法
public static void reflectPrivateMethod2() {
try {
Class> classAvenger = Class.forName("com.lah.reflect.Avenger");
Method methodBook = classAvenger.getDeclaredMethod("talkToSomeone", int.class, int.class , String.class);//注释6
methodBook.setAccessible(true);
Object objectBook = classAvenger.newInstance();
String string = (String) methodBook.invoke(objectBook,98,99, "haha");
System.out.println("reflectPrivateMethod2, string:" + string);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
注释4 处,反射调用方法,需要传入方法名,该方法需要的参数是 int 类型,所以用 int.class 。
注释5 处,给 answersQuestion 方法传入参数1 。
注释6 处,传入多个参数,写法和注释4类似。
运行结果,
Avenger{id=100,name=Avenger100}
reflectPrivateMethod, string:Your question is 2
Talk msg(haha) to 98 and 99
reflectPrivateMethod2, string:talk well