java反射详解实战代码

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;

        Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

Class反射机制

  1. 指的是可以于运行时加载,探知和使用编译期间完全未知的类.
  2. 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已经加载的类,能够知道这个类的所有属性和方法;对于任意一个对象,都能调用他的任意一个方法和属性;
  3. 加载完类之后,在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:反射。
  4. 每个类被加载进入内存之后,系统就会为该类生成一个对应的java.lang.Class对象,通过该Class对象就可以访问到JVM中的这个类.

Class对象的获取

  1. 对象的getClass()方法;
  2. 类的.class(最安全/性能最好)属性;
  3. 运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用).
        下面用代码展示一下:

[java]  view plain  copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4. import java.lang.reflect.Field;  
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 获取类的所有属性和方法及构造器 
  9.  * @create 2017-10-11 上午11:42:52 
  10.  * @version 1.0 
  11.  */  
  12. public class ReflectAllDemo {  
  13.   
  14.     /** 
  15.      * 获取类的所有属性和方法及构造器 
  16.      * @param args 
  17.      * @throws ClassNotFoundException  
  18.      * @create 2017-10-11 上午9:07:46 
  19.      */  
  20.     public static void main(String[] args) throws ClassNotFoundException {  
  21.           
  22.         //根据一个类的全名称获取类的类对象  
  23.         //如果类的全名称错误或者不存在,则会报类查询不到异常:ClassNotFoundException  
  24.         Class<?> clazz = Class.forName("java.lang.String");  
  25.           
  26.         //获取传递过来的类的所有方法  
  27.          Method[]    methods = clazz.getDeclaredMethods();  
  28.          for (Method method : methods) {  
  29.             System.out.println(method.toString());  
  30.         }  
  31.            
  32.         System.out.println("------------------------------我是分隔符:以下是类的属性--------------------------------");   
  33.         //获取传递过来的类的所有属性   
  34.         Field[] fields = clazz.getDeclaredFields();  
  35.         for (Field field : fields) {  
  36.             System.out.println(field.toString());  
  37.         }   
  38.           
  39.         System.out.println("------------------------------我是分隔符:以下是构造方法--------------------------------");  
  40.           
  41.         //获取传递过来的类的所有构造方法  
  42.         Constructor<?>[] constructor = clazz.getDeclaredConstructors();  
  43.         for (Constructor<?> ctt : constructor) {  
  44.             System.out.println(ctt.toString());  
  45.         }  
  46.           
  47.     }  
  48.   
  49. }  

创建对象

通过反射来生成对象的方式有两种:

  1. 使用Class对象的newInstance()方法来创建该Class对象对应类的实例(这种方式要求该Class对象的对应类有默认构造器).
  2. 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例(通过这种方式可以选择指定的构造器来创建实例).

调用方法

当获取到某个类对应的Class对象之后,就可以通过该Class对象的getMethod来获取一个Method数组或Method对象.

每个Method对象对应一个方法,在获得Method对象之后,就可以通过调用invoke方法来调用该Method对象对应的方法.

[java]  view plain  copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.InvocationTargetException;  
  4. import java.lang.reflect.Method;  
  5.   
  6. /** 
  7.  * 通过反射,对类中的方法进行操作 
  8.  * @create 2017-10-11 上午11:45:57 
  9.  * @version 1.0 
  10.  */  
  11. public class ReflectMethodDemo {  
  12.   
  13.     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {  
  14.           
  15.           
  16.         Class<?> clazz = Class.forName("com.lwl.reflect.Person");  
  17.         //获取对象  
  18.         Object instance = clazz.newInstance();  
  19. //      instance = clazz.getDeclaredConstructor(null).newInstance(null);  
  20.           
  21.         //如果已经知道方法的名称,那么调用起来更加方便  
  22.         Method method = clazz.getDeclaredMethod("setName"new Class[]{String.class});  
  23.         //设置值  
  24.         method.invoke(instance, new String[]{"jack"});  
  25.   
  26.         System.out.println(instance.toString());  
  27.           
  28.         //获取值  
  29.         Method getMethod = clazz.getDeclaredMethod("getName"new Class[]{});  
  30.         Object getValue = getMethod.invoke(instance, new String[]{});  
  31.         System.out.println(getValue);  
  32.           
  33.         //对对象中的静态方法进行访问  
  34.         Method staticMethod = clazz.getDeclaredMethod("printInfo"new Class[]{});  
  35.         //由于是静态方法,所以这里面的 instance 可以不传,只用用 null 表示  
  36.         Object staticValue = staticMethod.invoke(instance, new String[]{});  
  37. //       staticValue = staticMethod.invoke(null, new String[]{});  
  38.         System.out.println(staticValue);  
  39.           
  40.     }  
  41.   
  42. }  

访问成员变量

通过Class对象的的getField()方法可以获取该类所包含的全部或指定的成员变量Field,Filed提供了如下两组方法来读取和

设置成员变量值 .

  1. getXxx(Object obj): 获取obj对象的该成员变量的值, 此处的Xxx对应8中基本类型,如果该成员变量的类型是引用类型, 则取消get后面的Xxx;
  2. setXxx(Object obj, Xxx val): 将obj对象的该成员变量值设置成val值.此处的Xxx对应8种基本类型, 如果该成员类型是引用类型, 则取消set后面的Xxx;

[java]  view plain  copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 通过反射,对类中的字段进行操作 
  9.  * @create 2017-10-11 上午11:45:20 
  10.  * @version 1.0 
  11.  */  
  12. public class ReflectFieldDemo {  
  13.   
  14.     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {  
  15.           
  16.         //获取类对象  
  17.         Class<?> clazz = Class.forName("com.lwl.reflect.Person");  
  18.         //获取对象  
  19.         Object instance = clazz.newInstance();  
  20. //      instance = clazz.getDeclaredConstructor(null).newInstance(null);  
  21.           
  22.         //根据属性的名称 获取属性对象  
  23.         Field field = clazz.getDeclaredField("name");  
  24.         //获取属性的类型  
  25.         Class<?> type = field.getType();  
  26.         System.out.println(type); //out print class java.lang.String  
  27.           
  28.         //获取属性的名称  
  29.         String name = field.getName();  
  30.         System.out.println(name);  //out print name  
  31.           
  32.         //由于name属性是private,如果不设置setAccessible是无法直接对其进行设置  
  33.         //setAccessible是暴力破坏,如果是私有方法同理要设置  
  34.         field.setAccessible(true);  
  35.         field.set(instance, "张三");  
  36.           
  37.         System.out.println(instance.toString()); //out print Person [id=null, name=张三, address=null]  
  38.           
  39.     }  
  40.   
  41. }  

通过反射赋值

[java]  view plain  copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4. import java.lang.reflect.Field;  
  5. import java.lang.reflect.InvocationTargetException;  
  6. import java.lang.reflect.Method;  
  7.   
  8. /** 
  9.  * 通过反射,对类对象进行赋值操作 
  10.  * @create 2017-10-11 上午11:44:58 
  11.  * @version 1.0 
  12.  */  
  13. public class ReflectSetValueDemo {  
  14.   
  15.     /** 
  16.      * 用一句话说明这个方法做什么  
  17.      * @param args 
  18.      * @throws ClassNotFoundException  
  19.      * @throws SecurityException  
  20.      * @throws NoSuchFieldException  
  21.      * @throws NoSuchMethodException  
  22.      * @throws InvocationTargetException  
  23.      * @throws IllegalArgumentException  
  24.      * @throws IllegalAccessException  
  25.      * @throws InstantiationException  
  26.      * @create 2017-10-11 上午9:41:51 
  27.      */  
  28.     public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {  
  29.   
  30.         //获取类的Class的三种方式  
  31.         /* 
  32.          * 1. Class.forName(类名称全称:包括包名) 
  33.          * 2. 类.class  即:Person.class 
  34.          * 3. 对象.getClass()  new Person().getClass(); 
  35.          * */  
  36.         Class<?> clazz = Class.forName("com.lwl.reflect.Person");  
  37. //      clazz = new Person().getClass();  
  38. //      clazz = Person.class;  
  39.           
  40.         //获取一个属性  
  41.         Field field = clazz.getDeclaredField("address");  
  42.         System.out.println(field.toString());  
  43.           
  44.         System.out.println("--------------------------------------------我是分隔符:以下是对方法进行操作--------------------------------------------------------");  
  45.           
  46.         //获取一个方法  
  47.         Method method = clazz.getDeclaredMethod("getName"new Class[]{});  
  48.           
  49.         //传递的Class<?>的顺序要和方法的参数类型顺序保持一致,不然就无法匹配抛出异常:java.lang.NoSuchMethodException  
  50.         Method method1 = clazz.getDeclaredMethod("setName", String.class);  
  51.         //获取方法的名字  
  52. //      String name = method1.getName();  
  53.         Method method2 = clazz.getDeclaredMethod("setInfo", String.class,Integer.class);  
  54.         //method1 与 method2 还可以使用另外一种方式获取  
  55.         Method method3 = clazz.getDeclaredMethod("setName"new Class[]{String.class});  
  56.         Method method4 = clazz.getDeclaredMethod("setInfo"new Class[]{String.class,Integer.class});  
  57.           
  58.         System.out.println(method.toString());  
  59.         System.out.println(method1.toString());  
  60.         System.out.println(method2.toString());  
  61.         System.out.println(method3.toString());  
  62.         System.out.println(method4.toString());  
  63.           
  64.         System.out.println("--------------------------------------------我是分隔符:以下是对构造器进行操作--------------------------------------------------------");  
  65.         //因为默认构造器没有参数,使用可以传入null 或者 new Class[]{}  
  66.          Constructor<?> cs =  clazz.getDeclaredConstructor(new Class[]{});  
  67.          //带参数的构造器  
  68.          Constructor<?> cs2 =  clazz.getDeclaredConstructor(new Class[]{Integer.class,String.class,String.class});  
  69.          System.out.println(cs.toString());  
  70.          System.out.println(cs2.toString());  
  71.            
  72.            
  73.         System.out.println("--------------------------------------------我是分隔符:以下是对反射赋值进行操作--------------------------------------------------------");  
  74.         //根据类的默认构造器 创建一个类对象    
  75.         Object object = cs.newInstance(new Object[]{});  
  76. //      object = cs.newInstance(null);  
  77.         //根据类的带参数构造器,创建一个类对象  
  78.         Object object2 =    cs2.newInstance(new Object[]{1,"李四","南京"});  
  79. //      object2 = cs2.newInstance(null);  
  80.         System.out.println("原始的对象属性情况:"+object);   
  81.         System.out.println("原始的对象属性情况:"+object2);   
  82.           
  83.            
  84.         System.out.println("--------------------------------------------我是分隔符:以下是对反射赋值进行操作:设置开始--------------------------------------------------------");  
  85.           
  86.         //对属性进行设置值,先获取所有的方法  
  87.         Method[] methods = clazz.getDeclaredMethods();  
  88.         //获取类的所有属性  
  89.         Field[] fields = clazz.getDeclaredFields();  
  90.           
  91.         for (Method m : methods) {  
  92.             //获取方法的名称  
  93.             String name = m.getName();  
  94.             //如果名称是以set开头的,表示设置值  
  95.             if(name.startsWith("set")){  
  96.                 //获取set之后的字符串,即属性的名称  
  97.                 String fieldName = name.substring(3);  
  98.                 //因为set之后的首个字符串是大写,所以要截取第一个字符串转化为小写,这里千万别把所有的字符串都转化为小写,防止出现UserName 被转化为username  
  99.                 fieldName = fieldName.substring(01).toLowerCase() + fieldName.substring(1);  
  100.                 //这里会对类中的属性进行赋值  
  101.                 //由于Person里面一个特殊的setInfo的方法,且info不是类的属性,则不会进行赋值  
  102.                 setFieldValue(fieldName, fields, m, object);  
  103.             }  
  104.         }  
  105.         System.out.println("赋值后的对象属性情况:"+object);   
  106.         System.out.println("赋值后的对象属性情况:"+object2);   
  107.           
  108.     }  
  109.   
  110.     /** 
  111.      * 给类属性赋值  
  112.      * @param fieldName 
  113.      * @param fields 
  114.      * @param m 
  115.      * @param object 
  116.      * @throws IllegalAccessException 
  117.      * @throws IllegalArgumentException 
  118.      * @throws InvocationTargetException 
  119.      * @create 2017-10-11 上午10:41:53 
  120.      */  
  121.     public static void setFieldValue(String fieldName, Field[] fields, Method m,  Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{  
  122.           
  123.         for (Field field : fields) {  
  124.             if (field.getName().equals(fieldName)){  
  125.                 //获取字段的属性  
  126.                 Class<?> fieldClass = field.getType();  
  127.                 //如果是Integer 即知道这个是Person的ID  
  128.                 if(fieldClass == Integer.class){  
  129.                     //通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数  
  130.                     m.invoke(object, new Integer[]{1});  
  131.                 }  
  132.                 //因为同为String的有2个set方法,所有要通过属性名称判断到底是调用哪个  
  133.                 else if (fieldClass == String.class && "name".equals(fieldName)){  
  134.                     //通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数  
  135.                     m.invoke(object, new String[]{"jack"});  
  136.                 }  
  137.                 else if (fieldClass == String.class && "address".equals(fieldName)){  
  138.                     //通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数  
  139.                     m.invoke(object, new String[]{"南京"});  
  140.                 }  
  141.                 //不需要再次循环  
  142.                 return;  
  143.             }  
  144.         }  
  145.           
  146.     }  
  147.       
  148. }  

使用到的辅助类:

[java]  view plain  copy
  1. package com.lwl.reflect;  
  2.   
  3. public class Person {  
  4.   
  5.       
  6.     private Integer id;  
  7.       
  8.     private String name;  
  9.       
  10.     private String address;  
  11.   
  12.     public Person() {  
  13.     }  
  14.   
  15.     public Person(Integer id, String name, String address) {  
  16.         this.id = id;  
  17.         this.name = name;  
  18.         this.address = address;  
  19.     }  
  20.   
  21.     public Integer getId() {  
  22.         return id;  
  23.     }  
  24.   
  25.     public void setId(Integer id) {  
  26.         this.id = id;  
  27.     }  
  28.   
  29.     public String getName() {  
  30.         return name;  
  31.     }  
  32.   
  33.     public void setName(String name) {  
  34.         this.name = name;  
  35.     }  
  36.   
  37.     public String getAddress() {  
  38.         return address;  
  39.     }  
  40.   
  41.     public void setAddress(String address) {  
  42.         this.address = address;  
  43.     }  
  44.       
  45.     public void setInfo(String name,Integer id){  
  46.         this.id = id;  
  47.         this.name = name;  
  48.                   
  49.     }  
  50.   
  51.       
  52.     public static void printInfo(){  
  53.         System.out.println("我是静态方法,我被调用了");  
  54.     }  
  55.       
  56.     @Override  
  57.     public String toString() {  
  58.         return "Person [id=" + id + ", name=" + name + ", address=" + address  
  59.                 + "]";  
  60.     }  
  61.       
  62.       
  63.       
  64.       
  65. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值