• Java中的反射--Reflect


      在张孝祥老师的Java讲解中,学习到了Java反射的一部分知识,觉得有必要好好学习一下哈。

    一、反射的理解

    经典总结:反射就是把Java类中的各种成分映射成为相应的Java类

    例如:一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量、方法、构造方法、包等信息也用一个个的Java类来表示,表示Java类中的Class类显然要提供一系类的方法,来获得其中的变量、方法、构造方法、修饰类、包等信息,这些信息就是用相应的实例对象来表示,它们是Field、Method、Contructor、Package等

    反射的缺点:反射导致程序性能下降

    二、构造方法(Constructor)反射

    理解:就是获取到某一个Class类中的所有的构造方法Constructor类

    1 // 获得某个类的所有的构造方法
    2 Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
    3 
    4 // new String(new StringBuffer("abc"))
    5 // 得到String类的某一个构造方法
    6 Constructor constructor = String.class.getConstructor(StringBuffer.class);
    7 String str2 = (String) constructor.newInstance(new StringBuffer("abc"));

    三、成员变量(Field)反射

    理解:获取一个Class类中的成员变量的Field,以及通过反射获取其中某一个对象的成员变量的值

     1 public class ReflectPoint {
     2 
     3     private int x;
     4     public int y;
     5     
     6     public ReflectPoint(int x, int y) {
     7         super();
     8         this.x = x;
     9         this.y = y;
    10     }
    11 }
    12 
    13 ReflectPoint rf1 = new ReflectPoint(3, 5);
    14 // 获取Class类的Field成员变量,并没有指定是哪个对象的 fieldY不是对象上的变量,而是Class类上的变量,要用他去取某个对象上的值
    15 Field fieldY = rf1.getClass().getField("y");
    16 // 获取rf1这个对象的成员变量的值
    17 Object obj = fieldY.get(rf1);
    18 System.out.println(obj);
    19 
    20 // 获取Class类的Field成员变量,并没有指定是哪个对象的 这里x是私有的属性,但是也可以通过反射暴力获得
    21 Field fieldX = rf1.getClass().getDeclaredField("x");
    22 // 暴力反射
    23 fieldX.setAccessible(true);
    24 // 获取rf1这个对象的成员变量的值
    25 Object objX = fieldX.get(rf1);
    26 System.out.println(objX);

    注意:其中的注解也写的比较清楚,但是还想强调一下,Field类只是获取到了字节码中的成员变量,但是并没有获取到某一个特定对象的成员变量的具体的值

    成员变量反射的综合案例:

    题目:将任意一个对象中所有的String类型的成员变量所对应的字符串中的“b”转化成“a”,这其中用到了成员变量的反射,具体代码如下所示

     1 public class ReflectPoint {
     2 
     3     private int x;
     4     public int y;
     5     public String str1 = "ball";
     6     public String str2 = "basketball";
     7     public String str3 = "itcast";
     8     
     9     public ReflectPoint(int x, int y) {
    10         super();
    11         this.x = x;
    12         this.y = y;
    13     }
    14 }
    15 
    16     private static void changeStringValue(Object obj) throws Exception {
    17         Field[] fields = obj.getClass().getFields();
    18         for(Field field: fields){
    19             //if(field.getType().equals(String.class)){
    20             //这里就直接用 == 比较在内存中编译的字节码文件
    21             if(field.getType() == String.class){
    22                 String oldValue = (String) field.get(obj);
    23                 String newValue = oldValue.replace('b', 'a');
    24                 field.set(obj, newValue);
    25             }
    26         }
    27     }

    总结:其实这种反射的应用在spring框架的源码中应该是挺常见的,有时间去看看spring的源码,我想真正懂了反射的原理之后,再去读spring的源码的话,会轻松很多的!

    四、成员方法(Method)类

    理解:可以获取一个类中的成员方法

    1 String str1 = "abc";        
    2 
    3 Method methodCharAt = String.class.getMethod("charAt", int.class);
    4 // 注意这个invoke方法,这个是调用的意思,就是这个方法调用执行,传入new出来的对象以及参数
    5  System.out.println(methodCharAt.invoke(str1, 1));
    6 // 如果是静态方法的话,是不用传入new 出来的对象的,只需要传入参数即可
    7 // System.out.println(methodCharAt.invoke(null, 1));

    注意:静态方法,直接传入null即可,因为静态方法都是放在方法区中的,对象在栈中创建出来,就可以直接调用

    高能:用反射方式执行某个类中的main方法(写个程序,根据用户提供的类名,去执行该类中的main方法)

    为什么我很费劲的去用反射区调用main方法呢,这里其实可以引出一个前提条件,就是我并不知道到底是哪个类的main方法,但是类名可能就存在传递的参数中,我通过得到参数,得到类名,然后通过反射,启动main方法???

     1     static class TestArguments{
     2         public static void main(String[] args) {
     3             for(String arg:args){
     4                 System.out.println(arg);
     5             }
     6         }
     7     }
     8 
     9       //TestArguments.main(new String[]{"111","222","333"});
    10       String startingClassName = args[0];
    11       Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
    12       mainMethod.invoke(null, (Object) new String[]{"111","222","333"});
    13    //mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});

    五、数组(Array)反射

    直接上代码吧,数组的反射应该在开发框架中会得到使用,直接看一下简单的代码吧,当然那个Array是java中的reflect包中的类:java.lang.reflect.Array

     1     private static void printObject(Object obj1) {
     2         Class clazz = obj1.getClass();
     3         
     4         if(clazz.isArray()){
     5             int len = Array.getLength(obj1);
     6             for(int i=0;i<len;i++){
     7                 System.out.println(Array.get(obj1, i));
     8             }
     9         }else{
    10             System.out.println(obj1);
    11         }
    12     }
    13 
    14         printObject(obj1);
    15         printObject(new int[]{1,2,3});
  • 相关阅读:
    数据结构与算法10 微服务接口的鉴权和限流 [MD]
    .Net开发环境配置[OS/IIS/VS...]
    一、单件模式
    正则表达式调试器1.1
    C#2.0新特性系列文章转载
    巧用VS2005解决VS2005网站发布不便问题
    配置VS2005,加速VS2005运行速度
    转载:ASP.NET运行机制 和 图片盗链问题
    ASP.NET页面提前处理问题
    关于NTLM认证的python和.NET实现
  • 原文地址:https://www.cnblogs.com/ssh-html/p/10633801.html
Copyright © 2020-2023  润新知