Java反照详解版权声明

原创
小哥 2年前 (2022-12-30) 阅读数 68 #大杂烩

目录

反思反思,程序员的幸福!

回到顶部

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/

本文版权归作者所有,欢迎转载,但未经作者同意不得转载,否则保留追究法律责任的权利。

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

热门