• 2010年Java高新技术A(2)反射


    ava的反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方 法,对于任意一个对象都能够调用它的任意一个方法,这种动态获取的信息,以及动态java反射机制主要提供了以下功能。在运行时判断任意一个对象所属的 类,在运行时构造任意一个类的对象,在运行时判断任意一个类所具有的成员变量和方法,在运行时调用任意一个对象的方法,生成动态代理。

    【Java可以加载一个运行时才得知名称的class,获得其完整结构。】

    java的反射机制的实现要借助4个类

    ClassConstructor File Method;

    1、Class类

     代表java类。做个类比 人可以抽象为Person类,同样java中的类 可以抽象为Class

    那么Class的各个实例对象又是什么呢,是对应各个类在内存中的字节码,例如 Person类的字节码,ArrayList类的字节码等等。每个类的字节码对象只有唯一一个。我们大可以把它看成是封装了类的信息。如果我们拿到了 Class中的实例那我们就可以通过反射运用其中的成员以及方法了,那么我们怎么获得一个类的实例对象呢。有如下几种方法 

    1. Boolean var1 = true;  
    2. Class<?> classType2 = var1.getClass();  
    3.  System.out.println(classType2);  
    4. 输出结果class java.lang.Boolean  

    2)运用.class 语法

    1. Class<?> classType1 = Boolean.class;  
    2.         System.out.println(classType1);  
    3.         输出结果class java.lang.Boolean  

    3)通过 static method Class.forName() 这个方法在用的时候要捕获异常

    1. Class<?> classType3 =Class.forName("java.lang.Boolean");  
    2.         System.out.println(classType3);  
    3.         输出结果class java.lang.Boolean  

    当获取类名的时候,是不知道此类的名称的,forName(字符串参数)方法中传入字符串型的变量作为对外访问的入口,即传入什么类名就获得什么类名,就是配置文件里面的那个className = java.lang.Boolean 实际用的时候这样Class.forName(className)

     现在我们已经得到classType3了那么就可以创建一个Boolean实例了

            利用ClassnewInstance()方法相当于调用类的默认的构造器

           Object o = classType3.newInstance();

           这样我们就创建了一个对象,缺点是我们只能利用默认构造函数,因为Class的newInstance是不接受参数的。我们若是想传递进去参数可以自己构造一个。还有一个缺点是当类中的构造方法是私有时,我们仍不能实例化其对象。

    2、Constructor类 

    定义一个测试类  RoleDemo

    1. package cn.itheima.fanshe;  
    2. class RoleDemo   
    3. {  
    4.     public static void sop(Object obj){  
    5.         System.out.println(obj);  
    6.     }   
    7.     private String name;  
    8.     private String type;  
    9.     public String shuxing;  
    10.     public String str1 ="abcd";  
    11.     public String str2 ="aefgh";  
    12.     //构造器 Constructors  
    13.     public RoleDemo(){  
    14.         sop("默认构造器被调用");  
    15.     }  
    16.     //私有构造器  
    17.     RoleDemo(String name){  
    18.         this.name = name;  
    19.         sop("带参数的私有构造器被调用");  
    20.     }  
    21.     RoleDemo(String name,String type,String shuxing){  
    22.         this.name = name;  
    23.         this.type = type;  
    24.         this.shuxing = shuxing;  
    25.         sop("调用了带三个属性的构造器");  
    26.     }  
    27.     //get set 方法  
    28.      public String getName() {  
    29.          return name;  
    30.      }  
    31.      public void setName(String name) {  
    32.          this.name = name;  
    33.      }  
    34.      public String getType() {  
    35.          return type;  
    36.      }  
    37.      public void setType(String type) {  
    38.          this.type = type;  
    39.      }  
    40.       //override the toString method to show the class  
    41.      @Override  
    42.      public String toString(){  
    43.         // return "调用 roledemo的是 "+this.name+" : "+this.type+" : "+this.shuxing;  
    44.          return str1+" : "+str2;  
    45.      }  
    46. }  


    Constructor类代表某个类中的一个构造方法

    1. //使用getDeclaredConstructors获取全部构造器  
    2.         //输出  private cn.itheima.fanshe.RoleDemo(java.lang.String)  
    3.     //  public cn.itheima.fanshe.RoleDemo()  
    4.        Constructor<?>[]   constructors = classType3.getDeclaredConstructors();  
    5.        for (Constructor<?> m : constructors)  
    6.        {  
    7.            System.out.println(m);  
    8.        }  
    9.          
    10.        //获取默认构造器  
    11.        //输出 public cn.itheima.fanshe.RoleDemo()  
    12.        constructors = classType3.getConstructors();  
    13.        for (Constructor<?> m : constructors)  
    14.        {  
    15.            System.out.println(m);  
    16.        }  

    3 File类

           File类代表某个类中的一个成员变量,通过反射可以得到某个类中的成员变量,并改变其属性

    public filed getField(String name); 返回一个Field对象,它反映此Class对象所表示的类或接口的指定公共成员字段

    public Field[] getFields() ;             返回一个包含某些Field对象的数组,这额对象反映此Class对象所表示的类或者接口的所有可访问公共字段、

    public Field gerDeclaredField(String name) 返回一个Field对象,该对象反映此Class对象所表示的类或接口的指定已声明字段

    public Field[] getDeclaredField() 返回Field对象的一个数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段

    1. // 使用getFields获取属性  
    2.        Field[] fields = classType3.getFields();  
    3.        for (Field f : fields)  
    4.        {  
    5.            System.out.println(f);  
    6.        }  
    7. //返回值是  
    8. publicjava.lang.String  cn.itheima.fanshe.RoleDemo.shuxing 说明.getFields()方法返回的是该类的public属性;如果测试类有父类 同样会返回其父类的public属性。  
    9.   // 使用getDeclaredFields获取属性  
    10.        fields = classType3.getDeclaredFields();  
    11.        for (Field f : fields)  
    12.        {  
    13.            System.out.println(f);  
    14.        }  

    返回的结果是

    private java.lang.Stringcn.itheima.fanshe.RoleDemo.name

    private java.lang.Stringcn.itheima.fanshe.RoleDemo.type

    public java.lang.String cn.itheima.fanshe.RoleDemo.shuxing

    说明 getDeclaredFileds 返回的是所有的成员变量,若是测试类有父类,可以知道该方法并不返回父类的成员。

    4、 获取类的Method

           通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个势力的该方法

    返回一个Method对象,它反映此class对象所表示的类或接口的指定公共成员方法。

     public Method get Method(Stringname,class<?>… parameterTypes)

    返回一个包含某些Method对象的数组,这些对象反映此Class对象所表示的类或接口(包括那些由该类或者从超类和超接口继承的那些类或接口)的公共member方法

      public Method[] getMethods()

    返回一个Method对象,该对象反映此class对象所表示的类或接口的指定已声明的方法

    public Method getDeclareMethod(String name,Class<?>…parameterTypes);

    返回Method对象的一个数组,这些对象反映此Class对象表示的类或者接口声明的所有方法。但是不包括继承的方法

    1. public Method[] getDeclareMethods();  
    2. //使用getMethods获取函数  
    3.       Method[] methods =classType3.getMethods();  
    4.       for(Method m : methods)  
    5.       {  
    6.        System.out.println(m);  
    7.       }  
    8.       System.out.println();  
    9.    // 使用getDeclaredMethods获取函数   
    10.       methods = classType3.getDeclaredMethods();  
    11.       for (Method m : methods)  
    12.       {  
    13.           System.out.println(m);  
    14.       }  

    输出结果

    public static voidcn.itheima.fanshe.RoleDemo.sop(java.lang.Object)

    public java.lang.Stringcn.itheima.fanshe.RoleDemo.toString()

    public java.lang.Stringcn.itheima.fanshe.RoleDemo.getName()

    public voidcn.itheima.fanshe.RoleDemo.setName(java.lang.String)

    public java.lang.Stringcn.itheima.fanshe.RoleDemo.getType()

    public voidcn.itheima.fanshe.RoleDemo.setType(java.lang.String)

    public final native java.lang.Classjava.lang.Object.getClass()

    public native int java.lang.Object.hashCode()

    public boolean java.lang.Object.equals(java.lang.Object)

    public final native void java.lang.Object.notify()

    public final native void java.lang.Object.notifyAll()

    public final native void java.lang.Object.wait(long)throws java.lang.InterruptedException

    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

    public final void java.lang.Object.wait() throws java.lang.InterruptedException

     

    public static void cn.itheima.fanshe.RoleDemo.sop(java.lang.Object)

    public java.lang.Stringcn.itheima.fanshe.RoleDemo.toString()

    public java.lang.Stringcn.itheima.fanshe.RoleDemo.getName()

    public voidcn.itheima.fanshe.RoleDemo.setName(java.lang.String)

    public java.lang.Stringcn.itheima.fanshe.RoleDemo.getType()

    public voidcn.itheima.fanshe.RoleDemo.setType(java.lang.String)

    成员变量的反射示例  暴力反射私有成员变量

    1. RoleDemo rd1 = new RoleDemo("张三","type1","shuxing1");  
    2.     // 这个fsx是类上的变量,用它去获取某个对象上的值 输出 调用了带三个属性的构造器shuxing1  
    3.     Field fsx= rd1.getClass().getField("shuxing");  
    4.     System.out.println(fsx.get(rd1));  
    5.     Field fname= rd1.getClass().getDeclaredField("name"); //获取私有的变量  
    6.     fname.setAccessible(true); //暴力反射   
    7.     System.out.println(fname.get(rd1));  

    替换已有属性的值

    1. System.out.println(rd1);  
    2.         chengStringValue(rd1);  
    3.         System.out.println(rd1);  
    4.   
    5.   
    6. private static void chengStringValue(Object obj) throws Exception {  
    7.         Field[] fields = obj.getClass().getFields(); //获取穿进来的对象的String类型的变量  
    8.         for(Field field : fields ){  
    9.             if(field.getType()==String.class)  
    10.             {  
    11.                 String oldval = (String)field.get(obj); //获取对象上的值  
    12.                 String newval = oldval.replace('a','x');    //修改成一个新值将a换成x  
    13.                 field.set(obj, newval);                             //新值替换对象上的值  
    14.                   
    15.             }  
    16.         }  
    17.     }  

    输出结果

    调用了带三个属性的构造器

    abcd : aefgh

    xbcd : xefgh

     用反射的方法拿到某一个字节码文件,再用这个字节码文件得到其中的方法,用这个方法作用某一个对象。

     

    1. Method methodCharAt = String.class.getMethod("charAt"int.class);// int.class 是下面1的数据类型<span style="font-family: 微软雅黑, sans-serif; font- size: 9pt; ">                                                       </span>  
    1. System.out.println(methodCharAt.invoke(str1, 1));  

    说明:如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法

    调用一个类中的main方法

    1. //一般方式:  
    2.     Test.main(new String[]{"111","222","333"});  
    3.     System.out.println("-------");  
    4.       
    5.     //反射方式:  
    6.     String startingClassName = args[0];  
    7.     Method methodMain =  
    8.         Class.forName(startingClassName).getMethod("main",String[].class);  
    9.         //方案一:强制转换为超类Object,不用拆包 这是兼容JDK1.4的拆包动作          
    1. <span style="white-space:pre">      </span>methodMain.invoke(null,(Object)new String[]{"111","222","333"});  
    2.         //方案二:将数组打包,编译器拆包后就是一个String[]类型的整体  
    3.         methodMain.invoke(null,new Object[]{new String[]{"111","222","333"}});  
    4.     }  

    运行的时候run As-->Runconfigurations  --->(x)=Arguments 里加入cn.itheima.fanshe.textj即可看到结果

    调用了带三个属性的构造器
    111
    222
    333

    5、数组反射

    1)具有相同的维数和元素类型的数组属于同一个类型,即具有相同的class实例对象。

    2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

    3)基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用。非基本类型的一维数组,既可以仿作Object类型使用,又可以当做Object[]类型使用

    4)Array.asList()方法处理int[]和String[]时时有差异的

             Array.asList()方法会把String类型的数组会把数组中的每一个元素取出来,而对int[] 返回的是那个数组的对象,并不是数组中的元素

    5)Array工具类用于完成对数组的反射操作

             用反射的方式操作数组中的值,返回数组的长度。

    6)如何获得数组中元素的类型。

             只能获得数组中某一个元素的类型,并不能获得整个数组的类型

             Object[]a = new Object[](“a”,1);

             a[0].getClass().getName();

    反射的作用---->实现框架

    框架与框架要解决的核心问题

    我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。

    框架要解决的核心问题

    我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你以后写的类(门窗)呢?

    因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new 某个类的实例对象了,而要用反射方式来做。

  • 相关阅读:
    actionscript3.0 图片裁剪及保存jpg详解
    AS3 JPEG Encoder应用:从Flash中保存图片
    Kata 架构
    docker 学习笔记
    processon
    学习容器技术的思考
    cp -f 还是提示是否覆盖
    CentOS下安装桌面环境
    [PYTHON 实作] 算100
    <转>CentOS 7 安装配置 NFS
  • 原文地址:https://www.cnblogs.com/guwenren/p/3010948.html
Copyright © 2020-2023  润新知