• JAVA 反射


    1 利用反射创建一个无法通过new实例化的类的实例,并调用其私有方法进行数据传递
    首先创建一个无法实例化的类:Customer.java:
    public class Customer {
        private long id;
        private String name;
        private String age;
        
        private static Customer instance = null;
        /** 显示将构造函数声明为私有,外界无法通过new来实例化本类 */
        private Customer(){}
        private static synchronized Customer getInstance(){
            if(instance == null){
                return new Customer();
            }
            return instance;
        }
        
        /** 本set()方法为私有方法,外界无法直接为id属性赋值 */
        private void setId(long id) {
            this.id = id;
        }
        public long getId() {
            return id;
        }
        /** 本set()方法为私有方法,外界无法直接为name属性赋值 */
        private void setName(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        /** 本set()方法为私有方法,外界无法直接为age属性赋值 */
        private void setAge(String age) {
            this.age = age;
        }
        public String getAge() {
            return age;
        }
    }

    接下来,开始利用反射创建该类实例,并调用其私有化方法来为其属性赋值,最后调用其公开的方法验证其属性是否被赋上了值:
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;

    public class test {
        public static void main(String[] args) {
       //创建类的实例
         java.lang.Class c = null;
            Customer customer = null;
            try{
                c = Customer.class;
                Method m1 = c.getDeclaredMethod("getInstance");
                m1.setAccessible(true);//这句至关重要,不设置为true,便无法获取私有方法
                customer = (Customer)m1.invoke(c);
            } catch(Exception e){}
            
            try{
                java.lang.reflect.Field fieldId = customer.getClass().getDeclaredField("id");//获取私有成员变量id
                
                //获取私有方法setId(int id)
                String firstLetter = fieldId.getName().substring(0, 1).toUpperCase();
                String setName = "set" + firstLetter + fieldId.getName().substring(1);
                String getName = "get" + firstLetter + fieldId.getName().substring(1);
                java.lang.reflect.Method setMethod = customer.getClass().getDeclaredMethod(setName, new Class[]{fieldId.getType()});
                Method getMethod = customer.getClass().getDeclaredMethod(getName, new Class[]{});
                setMethod.setAccessible(true);//使私有方法可以被获取到
                setMethod.invoke(customer, new Object[]{ 23 });//调用该私有方法并传递数据
                
                System.out.println("-------------通过公共方法获取到的id值:" + customer.getId());
                System.out.println("-------------通过反射获取到的id值:" + getMethod.invoke(customer, null));
                
                //下面将模仿上面的这一段代码,通过反射来分别为name和age这两个私有成员变量赋值
                Field fieldName = customer.getClass().getDeclaredField("name");
                firstLetter = fieldName.getName().substring(0, 1).toUpperCase();
                setName = "set" + firstLetter + fieldName.getName().substring(1);
                setMethod = customer.getClass().getDeclaredMethod(setName, new Class[]{ fieldName.getType() });
                setMethod.setAccessible(true);
                setMethod.invoke(customer, "张三");
                System.out.println("-----------------姓名:" + customer.getName());
                
                Field fieldAge = customer.getClass().getDeclaredField("age");
                firstLetter = fieldAge.getName().substring(0, 1).toUpperCase();
                setName = "set" + firstLetter + fieldAge.getName().substring(1);
                setMethod = customer.getClass().getDeclaredMethod(setName, new Class[]{ fieldAge.getType() });
                setMethod.setAccessible(true);
                setMethod.invoke(customer, "40");
                System.out.println("-----------------年龄:" + customer.getAge());
            } catch(Exception e){}
        }
    }
    这里需要注意:java.lang.reflect.Method貌似是值对象,如果将其传递到另一个方法中并做处理,然后从那个方法中出来后,依然保持其原来的属性不变,没有一点引用类型对象的特征。
      同时,这里的Customer类虽然使用了一个单例模式,但如果我们使用反射的方法来实例化两个该对象实例,它们并非指向同一个引用,例如:
      private static Customer test1(){
            java.lang.Class c = null;
            Customer customer = null;
            try{
                c = Customer.class;
                Method m1 = c.getDeclaredMethod("getInstance");
                m1.setAccessible(true);//这句至关重要,不设置为true,便无法获取私有方法
                customer = (Customer)m1.invoke(c);
            } catch(Exception e){}
      }
      public static void main(String[] args) {
            Customer c1 = test1();
            Customer c2 = test1();
            System.out.println("-----------------------" + c1.equals(c2));
            System.out.println("-----------------------" + (c1 == c2));
        }
      编译后,两个都显示为false。

    利用java反射调用类的的私有方法

    今天和一位朋友谈到父类私有方法的调用问题,本来以为利用反射很轻松就可以实现,因为在反射看来根本不区分是否是private的,没有想到调用本 身的私有方法是可以的,但是调用父类的私有方法则不行,后来纠其原因很有可能是因为getDeclaredMethod方法和getMethod方法并不 会查找父类的私有方法,于是只好自己写递归了,经过尝试果然如此。把代码放出来方便更多人。这段代码可以解决很多实际问题,不过利用反射来做的话性能不会 太好。
    1. package com.syj.util.reflect;  
    2.   
    3. import java.lang.reflect.Method;  
    4.   
    5. /** 
    6.  * <p> 
    7.  * Title: 私有方法调用工具类 
    8.  * </p> 
    9.  *  
    10.  * <p> 
    11.  * Description:利用java反射调用类的的私有方法 
    12.  * </p> 
    13.  *  
    14.  * <p> 
    15.  * Copyright: Copyright (c) 2007 
    16.  * </p> 
    17.  *  
    18.  * @author 孙钰佳 
    19.  * @main sunyujia@yahoo.cn 
    20.  * @date Jun 1, 2008 10:18:58 PM 
    21.  */  
    22. public class PrivateUtil {  
    23.     /** 
    24.      * 利用递归找一个类的指定方法,如果找不到,去父亲里面找直到最上层Object对象为止。 
    25.      *  
    26.      * @param clazz 
    27.      *            目标类 
    28.      * @param methodName 
    29.      *            方法名 
    30.      * @param classes 
    31.      *            方法参数类型数组 
    32.      * @return 方法对象 
    33.      * @throws Exception 
    34.      */  
    35.     public static Method getMethod(Class clazz, String methodName,  
    36.             final Class[] classes) throws Exception {  
    37.         Method method = null;  
    38.         try {  
    39.             method = clazz.getDeclaredMethod(methodName, classes);  
    40.         } catch (NoSuchMethodException e) {  
    41.             try {  
    42.                 method = clazz.getMethod(methodName, classes);  
    43.             } catch (NoSuchMethodException ex) {  
    44.                 if (clazz.getSuperclass() == null) {  
    45.                     return method;  
    46.                 } else {  
    47.                     method = getMethod(clazz.getSuperclass(), methodName,  
    48.                             classes);  
    49.                 }  
    50.             }  
    51.         }  
    52.         return method;  
    53.     }  
    54.   
    55.     /** 
    56.      *  
    57.      * @param obj 
    58.      *            调整方法的对象 
    59.      * @param methodName 
    60.      *            方法名 
    61.      * @param classes 
    62.      *            参数类型数组 
    63.      * @param objects 
    64.      *            参数数组 
    65.      * @return 方法的返回值 
    66.      */  
    67.     public static Object invoke(final Object obj, final String methodName,  
    68.             final Class[] classes, final Object[] objects) {  
    69.         try {  
    70.             Method method = getMethod(obj.getClass(), methodName, classes);  
    71.             method.setAccessible(true);// 调用private方法的关键一句话  
    72.             return method.invoke(obj, objects);  
    73.         } catch (Exception e) {  
    74.             throw new RuntimeException(e);  
    75.         }  
    76.     }  
    77.   
    78.     public static Object invoke(final Object obj, final String methodName,  
    79.             final Class[] classes) {  
    80.         return invoke(obj, methodName, classes, new Object[] {});  
    81.     }  
    82.   
    83.     public static Object invoke(final Object obj, final String methodName) {  
    84.         return invoke(obj, methodName, new Class[] {}, new Object[] {});  
    85.     }  
    86.   
    87.     /** 
    88.      * 测试反射调用 
    89.      *  
    90.      * @param args 
    91.      */  
    92.     public static void main(String[] args) {  
    93.         PrivateUtil.invoke(new B(), "printlnA"new Class[] { String.class },  
    94.                 new Object[] { "test" });  
    95.         PrivateUtil.invoke(new B(), "printlnB");  
    96.     }  
    97. }  
    98.   
    99. class A {  
    100.     private void printlnA(String s) {  
    101.         System.out.println(s);  
    102.     }  
    103. }  
    104.   
    105. class B extends A {  
    106.     private void printlnB() {  
    107.         System.out.println("b");  
    108.     }  
    109. }  

    程序的输出结果为
    test
    b
    说明private方法调用成功了不管是自己的私有方法还是父类的私有方法。

    JAVA反射机制的学习

    JAVA语言中的反射机制:
        在Java 运行时 环境中,对于任意一个类,能否知道这个类有哪些属性和方法?
        对于任意一个对象,能否调用他的方法?这些答案是肯定的,这种动态获取类的信息,以及动态调用类的方法的功能来源于JAVA的反射。从而使java具有动态语言的特性。

      JAVA反射机制主要提供了以下功能:
          1.在运行时判断任意一个对象所属的类
          2.在运行时构造任意一个类的对象
          3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法)
          4.在运行时调用任意一个对象的方法(*****注意:前提都是在运行时,而不是在编译时)

      Java 反射相关的API简介:
          位于java。lang。reflect包中
            --Class类:代表一个类
            --Filed类:代表类的成员变量
            --Method类:代表类的方法
            --Constructor类:代表类的构造方法
            --Array类:提供了动态创建数组,以及访问数组的元素的静态方法。该类中的所有方法都是静态方法


    ----Class类
         在 java 的Object类中的申明了数个应该在所有的java类中被改写的methods:
    hashCode(), equals(),clone(),toString(),getClass()等,其中的getClass()返回yige
    Class 类型的对象。
         Class类十分的特殊,它和一般的类一样继承自Object,其实体用以表达java程序运行
    时的 class和 interface,也用来表达 enum,array,primitive,Java Types 以及关键字void
    ,当加载一个类,或者当加载器(class loader)的defineClass()被JVM调用,便产生一个Class
    对象,
         Class是Reflection起源,针对任何你想探勘的class(类),唯有现为他产生一个Class
    的对象,接下来才能经由后者唤起为数十多个的反射API。


         Java允许我们从多种途径为一个类class生成对应的Class对象。
              --运用 getClass():Object类中的方法,每个类都拥有此方法
                                    String str="abc";
                                    Class cl=str.getClass();


             --运用 Class。getSuperclass():Class类中的方法,返回该Class的父类的Class
             --运用 Class。forName()静态方法:
             --运用 ,Class:类名.class
             --运用primitive wrapper classes的TYPE语法: 基本类型包装类的TYPE,如:Integer.TYPE
                          注意:TYPE的使用,只适合原生(基本)数据类型

    ----运行时生成instance
         想生成对象的实体,在反射动态机制中有两种方法,一个针对无变量的构造方法,一个针对带参数的
    构造方法,,如果想调用带参数的构造方法,就比较的麻烦,不能直接调用Class类中的newInstance()
    ,而是调用Constructor类中newInstance()方法,首先准备一个Class[]作为Constructor的参数类型。
    然后调用该Class对象的getConstructor()方法获得一个专属的Constructor的对象,最后再准备一个
    Object[]作为Constructor对象昂的newInstance()方法的实参。
          在这里需要说明的是 只有两个类拥有newInstance()方法,分别是Class类和Constructor类
    Class类中的newInstance()方法是不带参数的,而Constructro类中的newInstance()方法是带参数的
    需要提供必要的参数。

        例:
          Class c=Class.forName("DynTest");
          Class[] ptype=new Class[]{double.class,int.class};
          Constructor ctor=c.getConstructor(ptypr);
          Object[] obj=new Object[]{new Double(3.1415),new Integer(123)};
          Object object=ctor.newInstance(obj);
          System.out.println(object);

    ----运行时调用Method
        这个动作首先准备一个Class[]{}作为getMethod(String name,Class[])方法的参数类型,接下来准备一个
    Obeject[]放置自变量,然后调用Method对象的invoke(Object obj,Object[])方法。
         注意,在这里调用

    ----运行时调用Field内容
        变更Field不需要参数和自变量,首先调用Class的getField()并指定field名称,获得特定的Field对象后
    便可以直接调用Field的 get(Object obj)和set(Object obj,Object value)方法

    java 代码
    1. package cn.com.reflection;   
    2.   
    3. import java.lang.reflect.Field;   
    4. import java.lang.reflect.InvocationTargetException;   
    5. import java.lang.reflect.Method;   
    6.   
    7. public class ReflectTester {   
    8.   
    9.     /**  
    10.      * 在这个类里面存在有copy()方法,根据指定的方法的参数去 构造一个新的对象的拷贝  
    11.      * 并将他返回  
    12.      * @throws NoSuchMethodException   
    13.      * @throws InvocationTargetException   
    14.      * @throws IllegalAccessException   
    15.      * @throws InstantiationException   
    16.      * @throws SecurityException   
    17.      * @throws IllegalArgumentException   
    18.      */  
    19.     public Object copy(Object obj) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{   
    20.            
    21.         //获得对象的类型   
    22.         Class classType=obj.getClass();   
    23.         System.out.println("该对象的类型是:"+classType.toString());   
    24.            
    25.         //通过默认构造方法去创建一个新的对象,getConstructor的视其参数决定调用哪个构造方法   
    26.         Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});   
    27.            
    28.         //获得对象的所有属性   
    29.         Field[] fields=classType.getDeclaredFields();   
    30.            
    31.         for(int i=0;i
    32.             //获取数组中对应的属性   
    33.             Field field=fields[i];   
    34.                
    35.             String fieldName=field.getName();   
    36.             String stringLetter=fieldName.substring(01).toUpperCase();   
    37.                
    38.             //获得相应属性的getXXX和setXXX方法名称   
    39.             String getName="get"+stringLetter+fieldName.substring(1);   
    40.             String setName="set"+stringLetter+fieldName.substring(1);   
    41.                
    42.             //获取相应的方法   
    43.             Method getMethod=classType.getMethod(getName, new Class[]{});   
    44.             Method setMethod=classType.getMethod(setName, new Class[]{field.getType()});   
    45.                
    46.             //调用源对象的getXXX()方法   
    47.             Object value=getMethod.invoke(obj, new Object[]{});   
    48.             System.out.println(fieldName+" :"+value);   
    49.                
    50.             //调用拷贝对象的setXXX()方法   
    51.             setMethod.invoke(objectCopy,new Object[]{value});   
    52.                
    53.                
    54.         }   
    55.            
    56.         return objectCopy;   
    57.            
    58.     }   
    59.        
    60.        
    61.     public static void main(String[] args) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {   
    62.         Customer customer=new Customer();   
    63.         customer.setName("hejianjie");   
    64.         customer.setId(new Long(1234));   
    65.         customer.setAge(19);   
    66.            
    67.         Customer customer2=null;   
    68.         customer2=(Customer)new ReflectTester().copy(customer);   
    69.         System.out.println(customer.getName()+" "+customer2.getAge()+" "+customer2.getId());   
    70.            
    71.         System.out.println(customer);   
    72.         System.out.println(customer2);   
    73.            
    74.   
    75.     }   
    76.   
    77. }   
    78.   
    79.   
    80. class Customer{   
    81.        
    82.     private Long id;   
    83.        
    84.     private String name;   
    85.        
    86.     private int age;   
    87.        
    88.        
    89.     public Customer(){   
    90.            
    91.     }   
    92.   
    93.     public int getAge() {   
    94.         return age;   
    95.     }   
    96.   
    97.   
    98.     public void setAge(int age) {   
    99.         this.age = age;   
    100.     }   
    101.   
    102.   
    103.     public Long getId() {   
    104.         return id;   
    105.     }   
    106.   
    107.   
    108.     public void setId(Long id) {   
    109.         this.id = id;   
    110.     }   
    111.   
    112.   
    113.     public String getName() {   
    114.         return name;   
    115.     }   
    116.   
    117.   
    118.     public void setName(String name) {   
    119.         this.name = name;   
    120.     }   
    121.        
    122. }  


    java 代码
    1. package cn.com.reflection;   
    2.   
    3. import java.lang.reflect.Array;   
    4.   
    5. public class ArrayTester1 {   
    6.   
    7.     /**  
    8.      * 此类根据反射来创建  
    9.      * 一个动态的数组   
    10.      */  
    11.     public static void main(String[] args) throws ClassNotFoundException {   
    12.            
    13.         Class classType=Class.forName("java.lang.String");   
    14.            
    15.         Object array= Array.newInstance(classType,10);  //指定数组的类型和大小   
    16.            
    17.          //对索引为5的位置进行赋值   
    18.         Array.set(array, 5"hello");   
    19.            
    20.         String s=(String)Array.get(array, 5);   
    21.            
    22.         System.out.println(s);   
    23.            
    24.            
    25.         //循环遍历这个动态数组   
    26.         for(int i=0;i<((String[])array).length;i++){   
    27.                
    28.             String str=(String)Array.get(array, i);   
    29.                
    30.             System.out.println(str);   
    31.         }   
    32.   
    33.     }   
    34.   
    35. }  
  • 相关阅读:
    day3:python测试题
    day4:Python列表(list)元组( tuple)字典(dict)
    day3:python运算符及数据类型(str)(int)
    2day:Python基础
    1day:了解python
    centos下安装storm
    Linux下添加,删除,修改,查看用户和用户组
    svn默认地址老发生改变,记下默认路径
    hive 遇到的问题及解决方法
    hadoop2.5.2 安装与部署
  • 原文地址:https://www.cnblogs.com/pricks/p/1543855.html
Copyright © 2020-2023  润新知