Java是一门安全性很高的语言,在编译时会对语法进行检查,有着严格的语法要求,正因为如此,它的灵活性略显不足。Java发射机制很好的补充了这个短板。
public class ClassOne { private final int param = 0; public final int param2 = 1; public int getParam(){ return param; } private void print(int i){ System.out.println(i); } }
首先我们创建一个ClassOne类,一会我们就用反射来获取这个类的信息。
try { Class C = Class.forName("ClassOne"); Object c = C.newInstance(); System.out.println(c.getClass()); } catch (Exception e){ e.printStackTrace(); }
这是一段简单的运用反射的代码,forName()方法通过类名获取到这个类ClassOne(当然这个类你要自己建啦),newInstance()方法可以调用类C的无参构造方法,创建一个C类的对象。由于反射不一定能够获得这个类,所以要用try catch包含。
Field[] field = C.getDeclaredFields();
获取类的参数,通过getDeclaredFields()方法,这个方法会返回一个数组,不仅包括那些public成员变量,还包括private的成员变量。
这里我们通过field.getModifiers()可以获得一个int型的值,它代表着这个成员变量的修饰符。
Modifier.toString(field[0].getModifiers())
可以把这个int型转换成对应的字符串,得到的结果是public static这样。
反射中调用方法
反射可以获得类的相关信息,不过更重要的是使用类中的方法。
在Java语言中,一切皆对象,甚至类也是对象,是Class类的对象,类的方法也是对象,是Method的对象。所以我们可以通过这么一行代码来获取所有的方法。
Method[] m = c.getMethods();
当然我们也可以获取特定的方法,比如ClassOne里的print方法。
确定一个方法需要两点
- 方法名
- 参数
Method method = c.getDeclaredMethod("print", int.class);
然后我们通过invoke()方法来调用这个方法。
method.invoke(classOne,3);
这样打印出来的是3,也就是我们调用成功了。
值得一提的一点:
反射是跳过编译,在运行时才进行的,所以有一些特殊的功能。比如跳过泛型,因为泛型是java在编译时为了防止我们出错而出现的产物。比如
ArrayList<String> list
要求list里的元素都是String类型的,不过我们可以通过反射来往里添加其他类型的元素。
ArrayList<String> list = new ArrayList<String>(); list.add("hello"); Class c = list.getClass(); Methodmethod=c.getMethod("add",Object.class); method.invoke(list,100); System.out.println(list.toString());
最后输出的结果是[hello, 100]