• java 反射demo


    基于类的反射
    Class 对象为您提供接入类元数据的反射的所有基本hook。这类元数据包括关于类自身的信息,如包和类的父类,以及该类实施的接口。它还包括该类定义的构造函数、字段和方法的详细信息。
    这些最后的项目都是编程中最经常使用的项目, 因此我将在本小节的稍后部分给出一些与它们协作的实例。 对于以下三类组件中的任何一类来说
    -- 构造函数、字段和方法 -- java.lang.Class 提供四种独立的反射调用,以不同的方式来获得信息。调用都遵循一种标准格式。以下是用于查找构造函数的一组反射调用: Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数, Constructor[] getConstructors() -- 获得类的所有公共构造函数 Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关) Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关) 每类这些调用都返回一个或多个 java.lang.reflect.Constructor 函数。这种 Constructor 类定义 newInstance 方法,
    它采用一组对象作为其唯一的参数,然后返回新创建的原始类实例。该组对象是用于构造函数调用的参数值。
    作为解释这一工作流程的实例,假设您有一个 TwoString 类和一个使用一对 String s的构造函数,如清单1所示: 清单1:从一对字符串创建的类
    &#160 1 2 3 4 5 6 7 public class TwoString { private String m_s1, m_s2; public TwoString(String s1, String s2) { m_s1 = s1; m_s2 = s2; } } 清单2中的代码获得构造函数并使用它来创建使用 String s "a" 和 "b" 的 TwoString 类的一个实例: 清单2:构造函数的反射调用 1 2 3 4 Class[] types = new Class[] { String.class, String.class }; Constructor cons = TwoString.class.getConstructor(types); Object[] args = new Object[] { "a", "b" }; TwoString ts = cons.newInstance(args);


    通过反射增加字段
    获得字段信息的 Class 反射调用不同于那些用于接入构造函数的调用,在参数类型数组中使用了字段名:
    Field getField(String name) -- 获得命名的公共字段
    Field[] getFields() -- 获得类的所有公共字段
    Field getDeclaredField(String name) -- 获得类声明的命名的字段
    Field[] getDeclaredFields() -- 获得类声明的所有字段
    尽管与构造函数调用类似,在字段方面仍存在一个重要的区别:前两个变量返回可以通过类接入的公共字段的信息 -- 即使它们来自于祖先类。后两个变量返回类直接声明的字段的信息 -- 与字段的接入类型无关。
    调用返回的 java.lang.reflect.Field 实例定义所有主类型的 getXXX 和 setXXX 方法,以及与对象引用协作的通用 get 和 set 方法。
    您可以根据实际的字段类型自行选择一种适当的方法,而 getXXX 方法将自动处理扩展转换(如使用 getInt 方法来检索一个字节值)。
    public class employee {
    private int id;
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public employee() {
        super();
        // TODO Auto-generated constructor stub
    }
    public employee(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    
    }
    import java.lang.reflect.Field;
    public class app {
        
        public int incrementField(String name, Object obj) throws Exception {
            Field field = obj.getClass().getDeclaredField(name);
            field.setAccessible(true);                                      //打开private访问权限   并修改该字段的值
            int value = field.getInt(obj) + 1;
            field.setInt(obj, value);
            return value;
        }    
        
    public static void main(String[] args) throws Exception {
        app a1= new app();
        int x=a1.incrementField("id", new employee(10,"xiaoming"));
        System.out.println(x);
    }
    }
    例如,如果对象为一个整数 count 值定义了 getCount 和 setCount 方法,您可以在一次调用中向该方法传递“count”作为 name 参数,以增加该值。
    清单4:通过反射增加一个JavaBean 属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public int incrementProperty(String name, Object obj) {
        String prop = Character.toUpperCase(name.charAt(0)) +
            name.substring(1);
        String mname = "get" + prop;
        Class[] types = new Class[] {};
        Method method = obj.getClass().getMethod(mname, types);
        Object result = method.invoke(obj, new Object[0]);
        int value = ((Integer)result).intValue() + 1;
        mname = "set" + prop;
        types = new Class[] { int.class };
        method = obj.getClass().getMethod(mname, types);
        method.invoke(obj, new Object[] { new Integer(value) });
        return value;
    }
    为了遵循JavaBeans惯例,我把属性名的首字母改为大写,然后预先考虑 get 来创建读方法名, set 来创建写方法名。JavaBeans读方法仅返回值,而写方法使用值作为唯一的参数,
    因此我规定方法的参数类型以进行匹配。最后,该惯例要求方法为公共,因此我使用查找格式,查找类上可调用的公共方法。 这一实例是第一个我使用反射传递主值的实例,因此现在我们来看看它是如何工作的。
    基本原理很简单:无论什么时候您需要传递主值,只需用相应封装类的一个实例(在 java.lang 包中定义)来替换该类主值。这可以应用于调用和返回。
    、因此,当我在实例中调用 get 方法时,我预计结果为实际
    int 属性值的 java.lang.Integer 封装。
    反射数组
    数组是Java编程语言中的对象。与所有对象一样,它们都有类。如果您有一个数组,使用标准 getClass 方法,您可以获得该数组的类,就象任何其它对象一样。
    但是, 不通过现有的实例来获得类不同于其它类型的对象。即使您有一个数组类,您也不能直接对它进行太多的操作
    -- 反射为标准类提供的构造函数接入不能用于数组,
    而且数组没有任何可接入的字段,只有基本的 java.lang.Object 方法定义用于数组对象。 数组的特殊处理使用 java.lang.reflect.Array 类提供的静态方法的集合。该类中的方法使您能够创建新数组,获得数组对象的长度,读和写数组对象的索引值。 清单5显示了一种重新调整现有数组大小的有效方法。它使用反射来创建相同类型的新数组,然后在返回新数组之前,在老数组中复制所有数据。 清单
    5:通过反射来扩展一个数组 1 2 3 4 5 6 7 public Object growArray(Object array, int size) { Class type = array.getClass().getComponentType(); Object grown = Array.newInstance(type, size); System.arraycopy(array, 0, grown, 0, Math.min(Array.getLength(array), size)); return grown; }
    清单 8:方法接入性能测试代码
    
    public int callDirectArgs(int loops) {
        int value = 0;
        for (int index = 0; index < loops; index++) {
            value = step(value);
        }
        return value;                        //使用直接变量 进行运算  ,直接求值并返回值       
    }
    public int callReferenceArgs(int loops) {
        TimingClass timing = new TimingClass();
        int value = 0;
        for (int index = 0; index < loops; index++) {
            value = timing.step(value);
        }
        return value;                              //使用 类的字段 进行运算 ,求值并返回值     
    }
    public int callReflectArgs(int loops) throws Exception {
        TimingClass timing = new TimingClass();
        try {
            Method method = TimingClass.class.getMethod
                ("step", new Class [] { int.class });
            Object[] args = new Object[1];
            Object value = new Integer(0);
            for (int index = 0; index < loops; index++) {              //使用反射字段  进行运算 ,求值并返回值。
                args[0] = value;
                value = method.invoke(timing, args);
            }
            return ((Integer)value).intValue(); 
        } catch (Exception ex) {
            System.out.println("Error using reflection");
            throw ex;
        }
    }
  • 相关阅读:
    数学角度看设计模式之观察者模式
    XML、JSON数据结构解析
    [理解ASP.NET Core框架]一个五十行的控制台Web
    .Net Core 学习 (1)
    SqlServer windowss身份登陆和sa身份登陆
    学习51单片机——秒表分享
    C语言中函数声明实现的位置
    java DOM4J 读取XML
    服务器与Linux操作系统基础原理
    Go语言实现数据结构(一)单链表
  • 原文地址:https://www.cnblogs.com/yimian/p/7954546.html
Copyright © 2020-2023  润新知