赞
踩
反射是一种可以间接操作目标对象的机制。当使用反射时,JVM 在运行的时候才动态加载类,对于任意类,知道其属性和方法,并不需要提前在编译期知道运行的对象是谁,允许运行时的 Java 程序获取类的信息并对其进行操作。
对象的类型在编译期就可以确定,但程序运行时可能需要动态加载一些类(之前没有用到,故没有加载进 jvm),使用反射可以在运行期动态生成对象实例并对其进行操作。
在获取到 Class 对象之后,反向获取和操作对象的各种信息。
我们先建一个类
public class People { private int age; private String name; private People() { age = 18; name = "Tony"; } public People(int age,String name) { this.age = age; this.name = name; } private void print() { System.out.println(this.toString()); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
获取 Class 对象有三种方法:
在运行期间,一个类只能有一个 Class 对象产生
通过 getDeclaredConstructors 方法我们可以得到类的所有构造方法。
public class Test { public static void main(String[] args) { Class c = People.class; //得到类的所有构造方法 Constructor[] constructors = c.getDeclaredConstructors(); for(int i = 0; i < constructors.length; i++) { //获得构造方法的类型 System.out.println("构造方法的类型:" + Modifier.toString(constructors[i].getModifiers())); //获得构造方法的所有参数 Class[] parametertypes = constructors[i].getParameterTypes(); for (int j = 0; j < parametertypes.length; j++) { System.out.print(parametertypes[j].getName() + " "); } System.out.println(""); } } }
返回结果如下:
通过该方法,我们可以获取类中所有构造方法和构造方法中的参数。
在 getDeclaredConstructor 方法中,我们未传入参数,表示希望得到类的特定构造方法。同时在代码中要进行异常捕获,因为可能不存在对应的构造方法。
public class Test { public static void main(String[] args){ Class c = People.class; Constructor constructor; try { //得到类的特定构造方法,无参构造方法不传参数 constructor = c.getDeclaredConstructor(); //获得构造方法的类型 System.out.println("构造方法的类型:" + Modifier.toString(constructor.getModifiers())); //获得构造方法的所有参数 System.out.println("构造方法的参数:"); Class[] parametertypes = constructor.getParameterTypes(); for (int j = 0; j < parametertypes.length; j++) { System.out.print(parametertypes[j].getName() + " "); } } catch (Exception e) {} } }
结果如下:
如果我们想得到这个构造函数
public People(int age,String name) {
this.age = age;
this.name = name;
}
在 getDeclaredConstructor 方法中,我们可以传入一个 Class 数组,里面包含 int 和 java.lang.String 的 Class 对象。
public class Test { public static void main(String[] args){ Class c = People.class; Class[] p = {int.class,String.class}; Constructor constructor; try { //得到类的特定构造方法,这次传入int和java.lang.String两个参数 constructor = c.getDeclaredConstructor(p); //获得构造方法的类型 System.out.println("构造方法的类型:" + Modifier.toString(constructor.getModifiers())); //获得构造方法的所有参数 System.out.println("构造方法的参数:"); Class[] parametertypes = constructor.getParameterTypes(); for (int j = 0; j < parametertypes.length; j++) { System.out.print(parametertypes[j].getName() + " "); } } catch (Exception e) {} } }
结果如下:
在上面。我们已经学习了如何获取类中特定的构造方法,在这里,我们不仅要获取,还要对类的构造方法进行调用。
我们先修改类的两个构造函数,分别加上一打印语句,代码如下:
private People() {
age = 18;
name = "Tony";
System.out.println("private People()调用成功");
}
public People(int age,String name) {
this.age = age;
this.name = name;
System.out.println("public People(int age,String name)调用成功");
}
我们先使用这个 public 访问类型的构造函数
public class Test {
public static void main(String[] args){
Class c = People.class;
Class[] p = {int.class,String.class};
Constructor constructor;
try {
constructor = c.getDeclaredConstructor(p);
//创建实例
constructor.newInstance(10,"HaWei");
} catch (Exception e) {}
}
}
结果如下
那么我们如何通过反射调用类的 private 访问类型的构造函数呢?其实大体与上面一样,只是我们需要设置constructors.setAccessible(true);
罢了。
public class Test {
public static void main(String[] args){
Class c = People.class;
Constructor constructor;
try {
//获取类的无参构造函数
constructor = c.getDeclaredConstructor();
constructor.setAccessible(true);
//创建实例
constructor.newInstance();
} catch (Exception e) {}
}
}
结果如下
我们尝试调用一下类的这个私有方法
private void print() {
System.out.println(this.toString());
}
关于调用方法,我们可以通过 getDeclaredMethod 来获取该方法,然后通过调用 invoke 执行。
public class Test { public static void main(String[] args){ Class c = People.class; Constructor constructor; try { //获取类的无参构造函数 constructor = c.getDeclaredConstructor(); constructor.setAccessible(true); //创建实例 People obj = (People) constructor.newInstance(); //获取需要调用的方法,需要两个参数,第一个参数是方法名,第二个参数是参数类型(本例不需要传入参数) Method method = c.getDeclaredMethod("print"); method.setAccessible(true); //调用方法,需要两个参数,第一个参数是类的实例,第二个参数是方法参数 method.invoke(obj); } catch (Exception e) {} } }
结果如下:
public class Test { public static void main(String[] args){ Class c = People.class; Constructor constructor; try { //获取类的无参构造函数 constructor = c.getDeclaredConstructor(); constructor.setAccessible(true); //创建实例 People obj = (People) constructor.newInstance(); //修改之前的name字段值 System.out.println("修改之前:" + obj.getName()); //获取类的name字段 Field field = c.getDeclaredField("name"); field.setAccessible(true); //修改类的私有字段 field.set(obj,"HaWei"); //修改之后的name字段值 System.out.println("修改之后:" + obj.getName()); } catch (Exception e) {} } }
结果如下:
可以在运行时获得类的内容,对于 Java 这种先编译再运行的语言,能够让我们很方便的写出灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。