zoukankan      html  css  js  c++  java
  • Reflection 反射

    版权声明:本文为博主原创文章。未经博主同意不得转载。

    https://blog.csdn.net/A__17/article/details/30571923

    1。概念:所谓的反射。能够理解为在运行时获取对象类型信息的操作。
    
    2,说明:
    
    	1)Class对象是在载入类时由虚拟机以及通过调用类载入器中的defineClass方法自己主动构造的。
    	2)一个类被类载入器载入到内存中,占用一片存储空间。这个空间里面的内容就是类的字节码,一个类在虚拟机中仅仅有一份字节码
    
    
    3,获得 Class 对象的三种方法:
    
    	1)调用Objec类的getClass()方法来得到Class对象。这也是最常见的产生Class对象的方法。
    		MyObject mobj = new MyObject(); 
    		Class c1 = mobj.getClass();
    
    	2)使用Class类的forName(String className)静态方法,className表示全限定名;如String的全限定名:java.lang.String;
    		Class c2 = Class.forName("java.lang.String");
    
    	3)调用某个类的class属性,即使用“类型名.class”来获取该类型相应的Class对象。

    注:基本类型和引用类型都有class属性 引用类型:Class c1 = MyType.class; 基本类型:Class c2 = int.class。 数组:Class c3 = double[].class; 注意: 基本类型(boolean、byte、char、short、int、long、float和double)以及keywordvoid通过调用自己的class属性能够得到其Class对象 说明:基本类型的包转类和Void类都有静态的TYPE字段。该字段返回的是他们基本类型的Class对象! 即:Integer.TYPE == int.class; 注意:int和Integer表示不同的数据类型,故int.class与Integer.class是不同的Class对象。所以Integer.TYPE与Integer.class也是不同的Class对象。 数组:全部具有同样元素类型和维数的数组都共享同一个Class对象,和数组元素长度、元素的值以及元素的顺序无关 4。Class类中的方法: 获得实现的接口: public Class<?>[] getInterfaces() 确定此对象所表示的类或接口实现的接口 获得构造方法: public Constructor<T> getConstructor(Class<?

    >... parameterTypes) 获得Class所表示类中用public修饰的指定构造器,注:当没有传入參数时,即 getConstructor() 返回的是默认的构造器 parameterTypes:是按声明顺序标识该方法形參类型的Class对象的一个数组 public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获得Class所表示类中指定的构造器,和訪问权限无关 public Constructor<?>[] getConstructors() 获得Class所表示类中全部用public修饰的构造器 public Constructor<?>[] getDeclaredConstructors() 获得Class所表示类中全部的构造器。和訪问权限无关 注:一个类的默认构造器的訪问权限和类的訪问权限一致 获得普通方法: public Method getMethod(String name, Class<?

    >... parameterTypes) 获得Class所表示类中用public修饰的指定方法 name:用于指定所需方法的简单名字 parameterTypes:是按声明顺序标识该方法形參类型的Class对象的一个数组 public Method[] getMethods() 获得Class所表示类中全部用public修饰的方法,包含继承过来的方法 public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获得Class所表示类中指定的方法,不包含继承过来的方法 public Method[] getDeclaredMethods() 获得Class所表示类中全部的方法,不包含继承过来的方法 获得字段: 与获得普通方法的方式一模一样。 获得内部类: public Class<?

    >[] getClasses() 得到Class所描写叙述的类中全部用public修饰的内部类 public Class<?

    > getDeclaredClasses() 得到Class所描写叙述的类中全部的内部类 5,使用反射创建对象: 1)使用Class对象的newInstance方法: public T newInstance():创建此Class对象所表示的类的一个实例,相当于调用了表示类的默认构造方法 2)使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,即用指定的构造方法创建实例。

    1,得到一个指定的构造方法 2,调用构造方法(Constructor)对象的newInstance(Object... initargs)方法 public T newInstance(Object... initargs) initargs表示构造器须要传入的实际參数 6,忽略訪问权限(暴力反射) 使用java.lang.reflect.AccessibleObject类中的setAccessible(boolean flag)方法,当flag为true的时候。就会忽略訪问权限(自然也可訪问到私有的成员) 注:Field、 Method、Constructor都继承了AccessibleObject类 7。使用反射调用方法 说明:每一个Method的对象相应一个详细的底层方法。获得Method对象后。程序能够使用Method里面的invoke方法来运行该底层方法 public Object invoke(Object obj, Object... args):对带有指定參数(args)的指定对象(obj)调用由此 Method 对象表示的底层方法 obj - 调用底层方法的对象 args - 用于方法调用的參数,一般使用 new Object[]{arg1,arg2} 的形式。 调用带有可变參数的方法: 要点:把可变參数当作数组參数。 如:show(String... s)作为show(String[] s)调用; show(T... a)作为show(Object[] a)调用; 说明: 1)若可变參数元素类型是引用类型: JDK内部接收到參数之后,会自己主动拆包取出參数再分配给该底层方法,为此我们须要把这个数组实參先包装成一个Object对象或者把实际參数作为一个Object一维数组的元素再传递。 2)若可变參数元素类型是基本类型: JDK内部接收到參数之后,不会拆包,所以能够不必再封装,只是封装了也不会错 结论:无论基本类型还是引用类型都使用Object[]{arg1,arg2}封装一层,保证无误 样例:使用反射运行Arrays类中的 public static <T> List<T> asList(T... a) {}方法(注:static后面的<T>:声明使用T来作为泛型) Class<Arrays> clazz = Arrays.class; // 把可变參数:T... a 当作数组參数:Object[] a Method m = clazz.getMethod("asList", Object[].class); Object value = m.invoke(null, new Object[]{new String[]{"1","2","3"}}); System.out.println(value); 注意: 1)假设底层方法是静态的,那么能够忽略指定的obj參数,该參数能够为null 2)假设底层方法所需的形參数为0,则所提供的args能够为:省略、null、或 new Object[]{} 3)返回值: 若底层方法的返回值是基本类型。则首先将其包装成对象,然后返回该对象 若底层方法的返回类型为void。则返回null 若底层方法返回的是数组对象,则方法返回该数组对象。注意:假设是基本类型的数组。数组元素没有进行包装,仍返回基本类型的数组对象 注:能够使用java.lang.reflect.Array类的get方法,获得数组对象的值 public static Object get(Object array, int index) 说明:返回数组对象中指定索引元素的值。假设该值是一个基本类型的值,则自己主动将其包装在一个对象中。 注意:假设指定的对象不是一个数组,将抛出IllegalArgumentException异常 举例: for (int i = 0; i < Array.getLength(array); i++) { System.out.println(Array.get(array, i)); } 8。使用反射操作字段: Field提供两组方法操作字段 获得字段对象(Field)的值 public Object get(Object obj):返回指定对象上此 Field 表示字段的值。假设该值是一个基本类型值,则自己主动将其包装在一个对象中。 obj:字段所属的对象。下同。 public xxx getXxx(Object obj):获取obj对象该Field的字段值,此处的xxx表示8个基本数据类型。若该字段的类型是引用数据类型则使用:Object get(Object obj); 设置字段对象(Field)的值 public void set(Object obj, Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值。假设底层字段的类型为基本类型。则对新值进行自己主动解包。

    public void setXxx(Object obj,xxx val):将obj对象的该Field字段设置成val值,此处的xxx表示8个基本数据类型。若该字段的类型是引用数据类型则使用:void set(Object obj, Object value); 訪问静态属性: 获取静态属性的值:field.get(null) 或 field.get(obj) 设置静态属性的值:field.set(null, string) 或 field.set(obj, string) Field提供的其它经常用法 public String getName() 返回此 Field 对象表示的字段的名称。 public Class<?

    > getType() 返回一个 Class 对象。它标识了此 Field 对象所表示字段的声明类型 public Type getGenericType() 返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型 9。反射的优化: 说明: 通过反射的方式创建对象 比 直接new对象 慢几倍 通过反射的方式訪问对象的属性 比 直接訪问对象的属性 慢几百倍 通过反射的方式调用对象的方法 比 直接调用对象的方法 慢几百倍 反射效率较低的原因: 通过反射訪问对象的属性或方法时,须要遍历该对象全部的属性或方法。这是反射效率低的主要原因。 通过反射訪问对象的属性或方法时,须要进行一些安全检查,以保证该类的属性或方法被安全的訪问。 优化: 1>将Field、Method等对象(使用一个Map)缓存起来。訪问时直接从缓存中获取Field、Method对象。 2>在缓存Field、Method等对象前,忽略它们的訪问权限: eg: // 将Field、Method等对象缓存起来 Field nameField = Person.class.getField("name"); Method helloMethod = Person.class.getMethod("hello"); nameField.setAccessible(true); helloMethod.setAccessible(true); HashMap<String, Field> fieldMap = new HashMap<>(); HashMap<String, Method> methodMap = new HashMap<>(); fieldMap.put("Person_field_name", nameField); methodMap.put("Person_method_hello", helloMethod); // 訪问属性或方法时直接从缓存中拿到Field、Method等对象 fieldMap.get("Person_field_name").get(obj); // 訪问obj的name属性的值 methodMap.get("Person_method_hello").invoke(obj); // 调用obj的hello方法


  • 相关阅读:
    js实现方块弹珠游戏
    学习servlet时出现的一些问题
    简述JAVA类的生命周期
    JAVA高级之路----JAVA多线程
    小计Tomcat的调优思路
    java生成pdf
    git分支在团队中的使用
    程序员修炼内功心法
    学会学习
    如何快速阅读
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10484392.html
Copyright © 2011-2022 走看看