反射(Reflection)的作用:
- 反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能。
- 反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的代码。
- 测试时可以利用反射API访问类的私有成员,以保证测试代码覆盖率。
API
获取Class对象
1 2 3 4 5 6 7 8 9 10
|
Class clz = Class.forName("java.lang.String");
Class clz = String.class;
String str = new String("Hello"); Class clz = str.getClass();
|
创建对象
如果默认无参构造函数是public,则可以直接使用class.newInstance(),而如果没有,则需要使用getDeclaredConstructor。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| class Rectangle { public int x; public int y; }
class User { private String name; private int age;
public User(String name, int age) { this.name = name; this.age = age; } public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
public class TestPerformance {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { Class c1 = Rectangle.class; c1.newInstance(); Class user = User.class; user.getDeclaredConstructor(String.class, int.class).newInstance("zhangsan", 19); }
}
|
获取属性、方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Method[] methods = user.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getName()); }
Field[] fields = user.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName()); }
User user1 = new User("lisi", 20); Method method = user1.getClass().getMethod("setAge", int.class); method.setAccessible(true); method.invoke(user1, 88); System.out.println(user1);
|
这里需要注意的是,getDeclaredFields方法可以拿到私有属性,而getFields不行。
性能分析
虽然反射功能很强大,但在使用过程中要注意效率问题。因为:
- 因为接口的通用性,Java的invoke方法是传object和object[]数组的。基本类型参数需要装箱和拆箱,产生大量额外的对象和内存开销,频繁促发GC。
- 编译器难以对动态调用的代码提前做优化,比如方法内联。
- 反射需要按名检索类和方法,有一定的时间开销。
我们可以进行简单的测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Class c1 = User.class; long duration = 0; duration = System.currentTimeMillis(); for(int i=0; i<999999999;i++) { c1.newInstance(); } long current = System.currentTimeMillis(); System.out.println(current - duration);
for(int i=0; i<999999999;i++) { new User("zhangsan", 20); } System.out.println(System.currentTimeMillis() - current);
|
以上代码的输出结果,两者差距有近千倍!!!
参考