简介
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
相关类
Class类
在我们编写的Java程序中的类,都可以看作是Class类的实例。它提供的方法可以获取类、类中属性、类中构造器、类中方法等。
获取类的一些的方法
getClasses()/getDeclaredClasses()
getClasses()获取类中所有public类的数组
getDeclaredClasses()获取类中所有类的数组
public class test{
public static void main(String[] args){
for(Class class1:test.class.getClasses())
System.out.println(class1.getName());
System.out.print("\n");
for(Class class1:test.class.getDeclaredClasses())
System.out.println(class1.getName());
}
public class a{}
private class b{}
}
输出
test$a
test$b
test$a
getName()
返回类的完整路径名字。
System.out.println(String.class.getName());
输出
java.lang.String
getPackage()
返回类所在的包。
System.out.println(String.class.getPackage());
输出
package java.lang, Java Platform API Specification, version 1.8
getSuperclass()
获取父类。
System.out.println(String.class.getSuperclass().getName());
输出
java.lang.Object
getInterfaces()
获取类实现的接口的数组。
for(Class class1:String.class.getInterfaces())
System.out.println(class1.getName());
输出
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
forName(String className)
通过类名返回类的对象
try{
String a=(String)Class.forName("java.lang.String").getConstructor(String.class).newInstance("123");
System.out.println(a);
}catch(Exception e){}
输出
123
获取属性的一些的方法
getField(String name)/getDeclaredField(String name)
- getField(String name) 根据名字获取对应的public对象
- getDeclaredField(String name) 根据名字获取对应的对象
如在test类中设置了两个属性:
public int a;
private int b;
调用方法:
try{
System.out.println(test.class.getField("a"));
System.out.println(test.class.getField("b"));
}catch(Exception e){
System.out.println("Could not find "+e.getMessage());
}
输出
public int test.a
Could not find b
但若将getField替换为getDeclaredField就可找到b。
public int test.a
private int test.b
getFields()/getDeclaredFields()
- getFields() 获取类中所有public对象的数组
- getDeclaredFields() 获取类中所有对象的数组
获取构造器的一些的方法
getConstructor (Class...<?> parameterTypes)/getDeclaredConstructor(Class...<?> parameterTypes)
- getConstructor 根据输入的参数类型匹配对应的public构造方法。
- getDeclaredConstructor 根据输入的参数类型匹配对应的构造方法。
如在test类中设置以下两个属性和三个构造器(其中一个为private):
public int a;
public String b;
public test(){}
public test(int a,String b){
this.a = a;
this.b = b;
}
private test(int a){
this.a = a;
this.b = "private constructor";
}
然后分别使用getConstructor获取这两个构造器(一个无参数,一个有参数):
try{
test s = test.class.getConstructor(int.class,String.class).newInstance(1,"test");
System.out.println(s.a+" "+s.b);
s = test.class.getConstructor().newInstance();
System.out.println(s.a+" "+s.b);
s = test.class.getDeclaredConstructor(int.class).newInstance(2);
System.out.println(s.a+" "+s.b);
}catch(Exception e){
System.out.println(e.getMessage());
}
输出
1 test
0 null
2 private constructor
getConstructors()/getDeclaredConstructors()
- getConstructors() 获取所有public构造器
- getDeclaredConstructors() 获取所有构造器
获取方法的一些的方法
getMethod(String name, Class...<?> parameterTypes)/getDeclaredMethod(String name, Class...<?> parameterTypes)
- getMethod 根据输入的方法名,及参数类型获取类中对应的public方法
- getDeclaredMethod 根据输入的方法名,及参数类型获取类中对应的方法
如在test类中设置如下两个方法:
public static void publicMethod(String s){
System.out.println("this is a public method. Parameter: "+s);
}
private static void privateMethod(int i){
System.out.println("this is a private method. Parameter: "+i);
}
执行:
try{
Method method = test.class.getMethod("publicMethod",String.class);
method.invoke(null, "public");
method = test.class.getDeclaredMethod("privateMethod", int.class);
method.invoke(null, 1);
}catch(Exception e){
System.out.println(e.getMessage());
}
输出:
this is a public method. Parameter: public
this is a private method. Parameter: 1
getMethods()/getDeclaredMethods()
- getMethods() 获取类中所有public方法的数组
- getDeclaredMethods() 获取类中所有方法的数组
Field类
Field类代表类的属性
equals(Object obj)
判断两个field是否相等。
如在test类中设置一个属性:
public int a;
执行:
try{
Field field1 = test.class.getField("a");
Field field2 = test.class.getField("a");
System.out.println(field1.equals(field2));
}catch(Exception e){
System.out.println(e.getMessage());
}
输出:
true
get(Object obj)
获取一个实例中对应的属性值。
如在test类中设置两个属性(其中一个是静态属性):
public String a;
public static String b = "static field";
执行:
try{
Field field1 = test.class.getField("a");
Field field2 = test.class.getField("b");
test obj = new test("new test");
System.out.println(field1.get(obj));
System.out.println(field2.get(null));
}catch(Exception e){
System.out.println(e.getClass().getName()+" "+e.getMessage());
}
输出:
new test
static field
- 注:static属性不需要输入实例作为参数,输入null即可。
set(Object obj, Object value)
将实例obj中的对应field设置为value。
try{
Field field = test.class.getField("a");
test obj = new test("new test");
System.out.println(field.get(obj));
field.set(obj, "changed field");
System.out.println(field.get(obj));
}catch(Exception e){
System.out.println(e.getClass().getName()+" "+e.getMessage());
}
输出:
new test
changed field
静态变量也可以改变:
try{
Field field = test.class.getField("b");
System.out.println(field.get(null));
field.set(null, "changed field");
System.out.println(field.get(null));
}catch(Exception e){
System.out.println(e.getClass().getName()+" "+e.getMessage());
}
输出:
static field
changed field
Method类
invoke(Object obj, Object... args)
输入实例及参数,执行方法。(若为静态方法,obj可填null)
public static void publicMethod(String s){
System.out.println("this is a public method. Parameter: "+s);
}
try{
Method method = test.class.getMethod("publicMethod",String.class);
method.invoke(null, "public");
}catch(Exception e){
System.out.println(e.getMessage());
}
输出:
this is a public method. Parameter: public
Constructor类
newInstance(Object... initargs)
根据输入的参数,返回一个实例。
如在test类中设置如下属性、构造器:
public String a;
public test(String a){
this.a = a;
}
执行:
try{
Constructor constructor = test.class.getConstructor(String.class);
test obj = (test) constructor.newInstance("new test");
System.out.println(obj.a);
}catch(Exception e){
System.out.println(e.getMessage());
}
输出:
new test
应用
JUnit测试private方法
在lab4中,为了测试private方法,我使用了反射获取该方法。
Method method = FlightScheduleApp.class.getDeclaredMethod("importFromFile", LinkedList.class, LinkedHashMap.class, LinkedList.class, String.class);
method.setAccessible(true);
method.invoke(null,resources,map,entries,readFile(filePath));
Comments