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方法
Reflection 反射的更多相关文章
- 代替Reflection(反射)的一些方法
Reflection(反射)是深入学习.Net必须掌握的技能之一.最初学Reflection的时候,的确是被惊住了,原来还可以这样.只要给你一个Assembly, 你就能获取到其中所有的类型,根据类型 ...
- 代替Reflection(反射)的一些方法(转)
作者:JustRun 林肯: http://www.cnblogs.com/JustRun1983/p/3830764.html 代替Reflection(反射)的一些方法(转) 2014-07-08 ...
- Java进阶之reflection(反射机制)——反射概念与基础
反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见 ...
- Java Reflection 反射基础
反射基础: package reflection; /** * Created by : Infaraway * DATE : 2017/3/2 * Time : 23:06 * Funtion : ...
- List GroupBy真实用法,Reflection(反射)用法,Enum用法,正则,搜索下拉布局
1.List GroupBy 用法 var _roomProducts = homesingProducts.GroupBy(t => t.RoomName); RoomedProducts ...
- java学习--Reflection反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...
- PHP的Reflection反射机制
更多内容推荐微信公众号,欢迎关注: 原文地址: http://www.nowamagic.net/php/php_Reflection.php PHP5添加了一项新的功能:Reflection.这个功 ...
- C# 反射Reflection——反射反射程序员的快乐
一.什么是反射 反射Reflection:System.Reflection,是.Net Framework提供的一个帮助类库,可以读取并使用metadata. 反射是无处不在的,MVC-Asp.Ne ...
- Java之reflection(反射机制)——通过反射操作泛型,注解
一.反射操作泛型(Generic) Java采用泛型擦除机制来引入泛型.Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦.但是编译一旦完成,所有和泛型有关的类型 ...
- C# Reflection反射机制
一.反射 什么是反射 .Net的应用程序由几个部分:'程序集(Assembly)'.'模块(Module)'.'类型(class)'组成: 反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组 ...
随机推荐
- 基于vue2.0实现仿百度前端分页效果(二)
前言 上篇文章中,已经使用vue实现前端分页效果,这篇文章我们单独将分页抽离出来实现一个分页组件 先看实现效果图 代码实现 按照惯例,我们在冻手实现的时候还是先想一想vue实现组件的思路 1.需要提前 ...
- Hyperledger Fabric密码模块系列之BCCSP(四)
前面说过要找时间介绍一下bccsp包下面的工厂factory,so here it is. 通过factory目前可以获得两类BCCSP实例,一个是上文说的sw,还有一个是通过pkcs11实现的. B ...
- Visual Studio Ultimate 2013
简体中文版 SHA-1: 07313542D36ED8BEEF18520AA4F15E33E32C7F77 http://download.microsoft.com/download/0/7/5/0 ...
- c#实战开发:用.net core开发一个简单的Web以太坊钱包 (六)
今天就来开发一个C# 版的简易钱包 先回顾以前的内容 c#实战开发:以太坊Geth 命令发布智能合约 (五) c#实战开发:以太坊Geth 常用命令 (四) c#实战开发:以太坊钱包快速同步区块和钱包 ...
- [PHP] 算法-二位有序数组中查找的PHP实现
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 1.二 ...
- 列表与for循环
一.list列表 1.概述 变量:使用变量存储数据,但是,有一个缺点:一个变量每次只能存储一个数据 #需求:存储5个人的年龄,求他们的平均年龄 age1 = 29 age2 = 36 age3 = 3 ...
- 请输入经过encode编码的URL
美团门店映射: <?php $url = "http://manage.test.kdb.kudianbao.com/Branch/mt_mdysh1d"; $res = u ...
- Python全栈学习_day005作业
,有如下变量(tu是个元祖),请实现要求的功能 tu = (, , {,,)}, ]) a. 讲述元祖的特性 b. 请问tu变量中的第一个元素 "alex" 是否可被修改? c. ...
- 通过PHP来 获取文件内容 并且分割字符串 呈现在表格中
<?php $aaa = file_get_contents("names.txt"); $data = explode("\n", $aaa); for ...
- HTML命名规范
一.关于选择器的命名 W3C CSS2.1的 4.1.3 节中提到:标识符(包括选择器中的元素名,类和ID)只能包含字符[a- zA-Z0-9]和ISO 10646字符编码U+00A1及以上,再加 ...