05月25, 2020

Java - 反射

简介

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));

本文链接:http://blog.zireaels.com/post/java-reflect.html

-- EOF --

Comments