反射:
反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的方法,属性,构造方法等成员
与曾经普通的通过创建类对象再调用方法或者成员变量的方式完全不同
反射是通过获取Class对象,然后对Class对象里的数据执行相关操作的过程
Class类:
反射的前提:获取类的字节码对象,也就是Class类对象
下面例子均用一个Person类作例子:
public class Person {
private String name;
public int age;
private void eat() {
System.out.println(name + "吃饭");
}
public Person() {
}
public Person(String name) {
this.name = name;
}
private Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
方式1:通过类名.class获取
Class c = Person.class;
方式2:通过Object类的成员方法getClass()方法获取
Class c = new Person().getClass();
该方法较少用,因为得到Object类对象时就可以直接使用方法了,没有反射的必要
方式3:通过Class.forName("全类名")方法获取
Class c = Class.forName("test.Person");
3种方式创建的Class对象是完全一样的
Class类常用方法:
String getSimpleName( ) 获取简单类名字符串,仅类名
Class c = Person.class;
System.out.println(c.getSimpleName()); //输出:Person
String getName( ) 获取完整类名字符串,包名+类名
Class c = Person.class;
System.out.println(c.getName()); //输出:test.Person
T newInstance( ) 利用Class对象创建类的对象,JDK9过时
Class c = Person.class;
Object obj = c.newInstance(); //创建的对象都是Object类型
有了Class类对象,就可以获取构造方法对象、成员方法对象、成员变量对象
Constructor类:
类中的每一个构造方法对应一个Constructor对象
Constructor getConstructor(Class... parameterTypes) 根据参数类型获取public修饰的构造方法对象
Constructor getDeclaredConstructor(Class... parameterTypes) 根据参数类型获取任意构造方法对象
Class c = Person.class;
Constructor con1 = c.getConstructor(String.class);
//仅能获得public修饰的public Person(String name) 构造方法
Constructor con2 = c.getDeclaredConstructor(String.class,int.class);
//能获得private修饰的private Person(String name, int age)构造方法
getConstructor方法仅能获得public修饰的构造方法
getDeclaredConstructor方法能获得包括private修饰的所有构造方法
参数列表传入的是构造方法参数的类型Class对象,而不是确切的数值
若要创建无参构造方法的对象,则不用传入参数
Constructor[] getConstructors() 获取所有的public修饰的构造方法
Constructor[] getDeclaredConstructors() 获取所有构造方法,包括privat修饰的
Class c = Person.class;
Constructor[] con1 = c.getConstructors();
Constructor[] con2 = c.getDeclaredConstructors();
System.out.println(Arrays.toString(con1));
//输出:[public test.Person(java.lang.String), public test.Person()]
System.out.println(Arrays.toString(con2));
//输出:[public test.Person(java.lang.String), public test.Person(), private test.Person(java.lang.String,int)]
Constructor类常用方法:
T newInstance(Object... initargs) 根据指定参数创建对象
Class c = Person.class;
Constructor con1 = c.getConstructor(String.class);
Object obj = con1.newInstance("A人");
System.out.println(obj); //输出:Person{name='A人', age=0}
void setAccessible(true) 暴力反射,设置为可以直接访问私有类型的构造方法
Class c = Person.class;
Constructor con2 = c.getDeclaredConstructor(String.class,int.class);
con2.setAccessible(true); //暴力反射,可用私有构造方法创建对象
Object obj = con2.newInstance("B人",42);
System.out.println(obj); //输出:Person{name='A人', age=42}
Method类:
类中的每一个成员方法都是一个Method类对象
Method getMethod(String MethodName , class...params) 根据方法名和参数类型获得public方法对象
Method getDeclaredMethod(String MethodName , class...params) 根据方法名和参数类型获得任意方法对象
Class c = Person.class;
Method m1 = c.getMethod("setName", String.class); //只能获取public方法
Method m2 = c.getDeclaredMethod("eat"); //可以获取private方法
与Constructor对象类似,方法中没有Declared的方法都是只能获取public方法
有Declared的方法都是能获得包括private修饰的所有方法
Method[] getMethods() 获取所有的public修饰的成员方法数组,包括父类中
Class c = Person.class;
Method[] m1 = c.getMethods();
for (Method method : m1) {
System.out.println(method);
}
不难发现,getMethods()方法不仅获得本类中的所有public方法,还获取了父类Object类的public方法
Method[] getDeclaredMethods() 获取当前类中所有的方法,包含私有的,不包括父类中
Class c = Person.class;
Method[] m2 = c.getDeclaredMethods();
for (Method method : m2) {
System.out.println(method);
}
getDeclaredMethods()方法仅能获得本类中的方法,包括private修饰的
Method类常用方法:
Object invoke(Object obj, Object... args) 根据参数args调用对象obj的该成员方法
Class c = Person.class;
Method m1 = c.getDeclaredMethod("setName", String.class);
Object obj = c.newInstance();
m1.invoke(obj,"A人");
System.out.println(obj);
void setAccessible(boolean flag) 暴力反射,设置为可以直接调用私有修饰的成员方法
Class c = Person.class;
Method m1 = c.getMethod("setName", String.class);
Method m2 = c.getDeclaredMethod("eat");
Object obj = c.newInstance();
m1.invoke(obj,"A人 ");
m2.setAccessible(true);
m2.invoke(obj); //输出:A人 吃饭
Field类:
类中的每一个成员变量都是一个Field类对象
Field getField(String name) 根据属性名获得属性对象,只能获取public修饰的
Field getDeclaredField(String name) 根据属性名获得属性对象,包括private修饰的
Class c = Person.class;
Field f1 = c.getField("age");
Field f2 = c.getDeclaredField("name");
Field[] getFields() 获取所有的public修饰的属性对象,返回数组
Field[] getDeclaredFields() 获取所有的属性对象,包括private修饰的,返回数组
Class c = Person.class;
Field[] f1 = c.getFields();
Field[] f2 = c.getDeclaredFields();
System.out.println(Arrays.toString(f1)); //输出:[public int test.Person.age]
System.out.println(Arrays.toString(f2)); //输出:[private java.lang.String test.Person.name, public int test.Person.age]
Field类常用方法:
Object get(Object obj) 获取Filed对象的值
Class c = Person.class;
Field f1 = c.getField("age");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
f1.set(obj, 22);
System.out.println(f1.get(obj)); //输出:22
void set(Object obj, Object value) 给obj对象赋一个value值
Class c = Person.class;
Field f1 = c.getField("age");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
f1.set(obj,22);
System.out.println(obj); //输出:Person{name='null', age=22}
void setAccessible(true) 暴力反射,设置为可以直接访问私有类型的属性
Class c = Person.class;
Field f2 = c.getDeclaredField("name");
Constructor con = c.getDeclaredConstructor(String.class,int.class);
con.setAccessible(true);
Object obj = con.newInstance("小明",22);
f2.setAccessible(true); //设置暴力反射,可以获取和设置Field的值
System.out.println(f2.get(obj));
Class getType() 获取属性的类型,返回Class对象
Class c = Person.class;
Field f1 = c.getField("age");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
f1.set(obj, 22);
System.out.println(f1.getType()); //输出:int