对任意的一个Object实例,获取了它的Class,就可以获取一切信息,通过反射读写字段会破坏对象的封装性。
Java提供了一下方法来通过Class实例获取字段信息:
- Field getField(name): 根据字段名获取某个public的field(包括父类)
- Field getDeclaredField(name): 根据字段名获取当前类的某个field(不包括父类)
- Field[] getFields(): 获取所有public的field(包括父类)
- Field[] getDeclaredFields(): 获取当前类的所有字段(不包括父类)
public class FieldTest {
public static void main(String[] args) throws NoSuchFieldException {
Class clazz = Student.class;
System.out.println(clazz.getField("age"));
System.out.println(clazz.getField("name"));
System.out.println(clazz.getDeclaredField("address"));
}
class Student extends Person{
public int age;
private String address;
}
class Person{
public String name;
}
}
运行结果:
public int Reflect.FieldTest$Student.age
public java.lang.String Reflect.FieldTest$Person.name
private java.lang.String Reflect.FieldTest$Student.address
获取到一个Field对象,可以通过Field对象获取到该对象的名称、类型、修饰符、值等信息。
- getName(): 返回字段名称
- getType(): 返回字段类型,是一个Class实例
- getModifiers(): 返回字段的修饰符,是一个int,不同bit表示不同含义
Field s = String.class.getDeclaredField("value");
int j = s.getModifiers();
System.out.println(s.getName());
System.out.println(s.getType());
System.out.println(Modifier.isPublic(j));
System.out.println(Modifier.isAbstract(j));
System.out.println(Modifier.isPrivate(j));
System.out.println(Modifier.isStatic(j));
执行结果:
value
class [C
false
false
true
false
使用get(Object)方法获取Field的值
Object person = new Person("Mark");
Class claz = person.getClass();
Field fie = claz.getDeclaredField("name");
fie.setAccessible(true);//无论是public或者private,一律允许访问
Object value = fie.get(person);
System.out.println(value);
static class Person{
public String name;
public Person(String name){
this.name = name;
}
}
执行结果:
Mark
使用Field.set(Object,Object)实现设置字段值,第一个参数是指定的实例,第二个参数是待修改的值。
Person person = new Person("Mark");
System.out.println(person.getName());
Class claz = person.getClass();
Field fie = claz.getDeclaredField("name");
fie.setAccessible(true);//无论是public或者private,一律允许访问
//设置字段值
fie.set(person, "John");
System.out.println(person.getName());
运行结果:
Mark
John
2、 调用方法
通过Class实例可以获取所有Method的信息,Java提供了一下几个方法来获取Method。
- Method getMothod(name, Class…): 获取某个public的Method(包括父类)
- Method getDeclaredMethod(name, Class…): 获取当前类的某个Method(不包括父类)
- Method[] getMethods(): 获取所有public的Method(包括父类)
- Method[] getDeclareMethods(): 获取当前类的所有Method(不包括父类)
//反射获取方法
public class MethodTest {
public static void main(String[] args) throws NoSuchMethodException {
Class clazz = Student.class;
//有参public方法
System.out.println(clazz.getMethod("getScore", String.class));
//有参private方法
System.out.println(clazz.getDeclaredMethod("getPhone", int.class));
//无参public父类方法
System.out.println(clazz.getMethod("getName"));
}
class Student extends Person{
public int getScore(String score){
return 100;
}
private int getPhone(int phone){
return 12345;
}
}
class Person{
public String getName(){
return "Mark";
}
}
}
执行结果:
public int Reflect.MethodTest$Student.getScore(java.lang.String)
private int Reflect.MethodTest$Student.getPhone(int)
public java.lang.String Reflect.MethodTest$Person.getName()
获取到Method对象,就可以获取该方法的所有信息,java提供了以下方法对方法进行操作:
- getName(): 返回方法名称
- getReturnType(): 返回方法返回值类型,是一个Class实例
- getParameterTypes(): 返回方法的参数类型,是一个Class数据
- getModifiers():返回方法的修饰符,是一个int类型,不同数字代表不同含义
//获取方法的详细信息
Method method = clazz.getMethod("getScore", String.class);
System.out.println(method.getName());//方法名
System.out.println(method.getReturnType());//返回类型
System.out.println(method.getParameterTypes());//方法参数类型
System.out.println(method.getModifiers());//方法的修饰符
执行结果:
getScore
int
[Ljava.lang.Class;@6ff3c5b5
1
2.1 调用方法
获取到一个Method方法时,不仅可以获取该方法对象的所有信息,还可以对方法进行操作。调用方法。
利用反射调用String的length()方法,使用Method的invoke方法就相当于调用该方法,invoke的第一个参数是对象实例,后面的可变参数与方法参数一致。
String str = "Hello World";
Method m1 = String.class.getMethod("length");
int length = (int) m1.invoke(str);
System.out.println(length);
调用非public方法,使用Method.setAccessible(true)方法
//调用private方法
User user = new User();
Method m2 = user.getClass().getDeclaredMethod("setName", String.class);
m2.setAccessible(true);
String band = (String) m2.invoke(user,"Oasis");
System.out.println(band);
static class User{
String name;
private String setName(String name){
return name;
}
}
执行结果:
Oasis
处理多态:子类覆写了父类的方法,从父类获取到的方法,作用于子类时,调用的是子类的方法。
结论:使用反射调用方法时,仍然遵守多态规则。
//处理多态
Method m3 = Animals.class.getMethod("run");
m3.invoke(new Cat());
class Animals{
public void run(){
System.out.println("Animals:I can run");
}
}
class Cat extends Animals{
public void run(){
System.out.println("Cat:I can run");
}
}
执行结果:
Cat:I can run



