Java反照详解版权声明
原创目录
反思反思,程序员的幸福!
1什么是反思?
Java反射处于运行状态,对于任何类,都可以知道该类的所有属性和方法;对于任何对象,都可以调用其任何方法和属性;并且可以更改其属性。这也是Java被认为是动态的(或准动态的,为什么它是准动态的?因为一般来说,动态语言的定义是程序运行时,允许更改程序结构或变量类型,所以这种语言被称为动态语言。从这个角度来看,Perl,Python,Ruby是一种动态语言,C++,Java,C#不是动态语言。)语言的关键属性。
2反思能做什么?
我们知道反射机制允许程序在运行时使用任何已知名称。class内部信息,包括modifiers(修饰符),fields(属性),methods(方法)并且可以在运行时更改。fields内容或通话methods。然后我们可以更灵活地编写代码,代码可以在运行时组装,而不需要组件之间的源代码链接,减少了代码的耦合;以及动态代理的实现等。;但需要注意的是,反射的不当使用会导致资源的高消耗!
3反思的具体实现
这是一门基础课 Person
1 package com.ys.reflex;
2 public class Person {
3 //私有属性
4 private String name = "Tom";
5 //公有属性
6 public int age = 18;
7 //构造方法
8 public Person() {
9 }
10 //私有方法
11 private void say(){
12 System.out.println("private say()...");
13 }
14 //公有方法
15 public void work(){
16 System.out.println("public work()...");
17 }
18 }
①、得到 Class 三种方式
1 //1,通过对象调用 getClass() 获取的方法,通常应用于:例如,您发送 Object
2 // 对象的类型,我不知道您是什么类,使用此方法
3 Person p1 = new Person();
4 Class c1 = p1.getClass();
5
6 //2直接通过 类名.class 获取的方式,该方法是最安全可靠的,程序性能更高。
7 // 这意味着任何类都有一个隐式静态成员变量。 class
8 Class c2 = Person.class;
9
10 //3、通过 Class 对象的 forName() 静态获取的方法,用的最多,
11 // 但可能会扔 ClassNotFoundException 异常
12 Class c3 = Class.forName("com.ys.reflex.Person");
需要注意的是: 一个类在 JVM 只有一个 Class 实例, 也就是说,我们得到了上述结果。 c1,c2,c3进行 equals 比较发现true
②、 通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等。
查阅 API 可以看到 Class 有很多方法:
getName():获取类的全名。
getFields():获取班级的public类型的属性。
getDeclaredFields():获取班级的所有属性。包括private 声明和继承的类
getMethods():获取班级的public类型的方法。
getDeclaredMethods():获取班级的所有方法。包括private 声明和继承的类
getMethod(String name, Class[] parameterTypes):获取班级的特定方法,name参数指定方法的名称,parameterTypes 参数指定方法的参数类型。
getConstructors():获取班级的public类型的构造方法。
getConstructor(Class[] parameterTypes):获取班级的特定构造方法,parameterTypes 该参数指定构造方法的参数类型。
newInstance()通过不带参数的类构造函数创建类的对象。
让我们用一个例子来演示上述方法:
1 //获取类的全名
2 String className = c2.getName();
3 System.out.println(className);//输出com.ys.reflex.Person
4
5 //获得类的public类型的属性。
6 Field[] fields = c2.getFields();
7 for(Field field : fields){
8 System.out.println(field.getName());//age
9 }
10
11 //获取类的所有属性。包括私人
12 Field [] allFields = c2.getDeclaredFields();
13 for(Field field : allFields){
14 System.out.println(field.getName());//name age
15 }
16
17 //获得类的public类型的方法。此处包含 Object 类的一些方法
18 Method [] methods = c2.getMethods();
19 for(Method method : methods){
20 System.out.println(method.getName());//work waid equls toString hashCode等
21 }
22
23 //获取类的所有方法。
24 Method [] allMethods = c2.getDeclaredMethods();
25 for(Method method : allMethods){
26 System.out.println(method.getName());//work say
27 }
28
29 //获取指定的属性
30 Field f1 = c2.getField("age");
31 System.out.println(f1);
32 //获取指定的私有属性
33 Field f2 = c2.getDeclaredField("name");
34 //启用和禁用访问安全检查的开关,值为 true指示使用时应取消反射对象 java 语言访问检查;否则未取消
35 f2.setAccessible(true);
36 System.out.println(f2);
37
38 //创建此类的对象
39 Object p2 = c2.newInstance();
40 //将 p2 对象的 f2 属性已分配 Bob,f2 属性即为 私有属性 name
41 f2.set(p2,"Bob");
42 //使用反射机制会破坏封装,导致java对象的属性不安全。
43 System.out.println(f2.get(p2)); //Bob
44
45 //获取构造方法
46 Constructor [] constructors = c2.getConstructors();
47 for(Constructor constructor : constructors){
48 System.out.println(constructor.toString());//public com.ys.reflex.Person()
49 }
4,基于反射获取父类属性
父类 Parent.java
1 public class Parent { 2 public String publicField = "parent_publicField"; 3 protected String protectField = "parent_protectField"; 4 String defaultField = "parent_defaultField"; 5 private String privateField = "parent_privateField"; 6 7 }
子类 Son.java
1 public class Son extends Parent { 2 }
测试类:
1 public class ReflectionTest { 2 3 @Test 4 public void testGetParentField() throws Exception{ 5 Class c1 = Class.forName("com.ys.model.Son"); 6 //获取父类私有属性值 7 System.out.println(getFieldValue(c1.newInstance(),"privateField")); 8 } 9 10 public static Field getDeclaredField(Object obj,String fieldName) { 11 Field field = null; 12 Class c = obj.getClass(); 13 for(; c != Object.class ; c = c.getSuperclass()){ 14 try { 15 field = c.getDeclaredField(fieldName); 16 field.setAccessible(true); 17 return field; 18 }catch (Exception e){ 19 //不要在这里做任何事!这里的异常必须这样写,不能抛出。 20 //如果此处的异常被打印或抛出,则不会执行它。c = c.getSuperclass(),最后,它不会进入父类。 21 } 22 } 23 return null; 24 } 25 public static Object getFieldValue(Object object,String fieldName) throws Exception{ 26 Field field = getDeclaredField(object,fieldName); 27 28 return field.get(object); 29 } 30 }
通过执行上述代码,我们获得父类的私有属性值。这里需要注意的是,父类的属性值不能通过反射直接获得子类的对象来获得,必须根据反射获得子类。 Class 调用中的对象 getSuperclass() 方法获取父类对象,然后通过父类对象获取父类属性值。
4,反思总结
灵活使用反射使我们的代码更加灵活,例如JDBC本地代码注册驱动程序,hibernate 实体类,Spring 的 AOP等等都有反射的实现。但任何事情都有两面性,反射也会消耗系统的性能,增加复杂性等,合理使用才是真的!
作者: YSOcean
出处: http://www.cnblogs.com/ysocean/
本文版权归作者所有,欢迎转载,但未经作者同意不得转载,否则保留追究法律责任的权利。
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除