Java 反射机制详解.docx
《Java 反射机制详解.docx》由会员分享,可在线阅读,更多相关《Java 反射机制详解.docx(20页珍藏版)》请在冰豆网上搜索。
![Java 反射机制详解.docx](https://file1.bdocx.com/fileroot1/2023-1/2/12c7eeac-5d7a-4616-808b-f32b56d3b86b/12c7eeac-5d7a-4616-808b-f32b56d3b86b1.gif)
Java反射机制详解
动态语言
动态语言,是指程序在运行时可以改变其结构:
新的函数可以被引进,已有的函数可以被删除等在结构上的变化。
比如众所周知的ECMAScript(JavaScript)便是一个动态语言。
除此之外如Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。
(引自:
XX百科)
varexecString="alert(Math.floor(Math.random()*10));";
eval(execString);
Class反射机制
∙指的是可以于运行时加载,探知和使用编译期间完全未知的类.
∙程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已经加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用他的任意一个方法和属性;
∙加载完类之后,在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:
反射。
InstancesoftheclassClassrepresentclassesandinterfacesinarunningJavaapplication.Anenumisakindofclassandanannotationisakindofinterface.EveryarrayalsobelongstoaclassthatisreflectedasaClassobjectthatissharedbyallarrayswiththesameelementtypeandnumberofdimensions(维度).TheprimitiveJavatypes(boolean,byte,char,short,int,long,float,anddouble),andthekeywordvoidarealsorepresentedasClassobjects.
∙每个类被加载进入内存之后,系统就会为该类生成一个对应的java.lang.Class对象,通过该Class对象就可以访问到JVM中的这个类.
Class对象的获取
∙对象的getClass()方法;
∙类的.class(最安全/性能最好)属性;
∙运用Class.forName(StringclassName)动态加载类,className需要是类的全限定名(最常用).
从Class中获取信息
Class类提供了大量的实例方法来获取该Class对象所对应的详细信息,Class类大致包含如下方法,其中每个方法都包含多个重载版本,因此我们只是做简单的介绍,详细请参考JDK文档
获取类内信息
获取内容
方法签名
构造器
ConstructorgetConstructor(Class
>...parameterTypes)
包含的方法
MethodgetMethod(Stringname,Class
>...parameterTypes)
包含的属性
FieldgetField(Stringname)
包含的Annotation
AgetAnnotation(ClassannotationClass)
内部类
Class
>[]getDeclaredClasses()
外部类
Class
>getDeclaringClass()
所实现的接口
Class
>[]getInterfaces()
修饰符
intgetModifiers()
所在包
PackagegetPackage()
类名
StringgetName()
简称
StringgetSimpleName()
一些判断类本身信息的方法
判断内容
方法签名
注解类型?
booleanisAnnotation()
使用了该Annotation修饰?
booleanisAnnotationPresent(Class
extendsAnnotation>annotationClass)
匿名类?
booleanisAnonymousClass()
数组?
booleanisArray()
枚举?
booleanisEnum()
原始类型?
booleanisPrimitive()
接口?
booleanisInterface()
obj是否是该Class的实例
booleanisInstance(Objectobj)
使用反射生成并操作对象:
MethodConstructorField这些类都实现了java.lang.reflect.Member接口,程序可以通过Method对象来执行相应的方法,通过Constructor对象来调用对应的构造器创建实例,通过Filed对象直接访问和修改对象的成员变量值.
创建对象
通过反射来生成对象的方式有两种:
∙使用Class对象的newInstance()方法来创建该Class对象对应类的实例(这种方式要求该Class对象的对应类有默认构造器).
∙先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例(通过这种方式可以选择指定的构造器来创建实例).
通过第一种方式来创建对象比较常见,像Spring这种框架都需要根据配置文件(如applicationContext.xml)信息来创建Java对象,从配置文件中读取的只是某个类的全限定名字符串,程序需要根据该字符串来创建对应的实例,就必须使用默认的构造器来反射对象.
下面我们就模拟Spring实现一个简单的对象池,该对象池会根据文件读取key-value对,然后创建这些对象,并放入Map中.
配置文件
{
"objects":
[
{
"id":
"id1",
"class":
"com.fq.domain.User"
},
{
"id":
"id2",
"class":
"com.fq.domain.Bean"
}
]
}
ObjectPool
/**
*Createdbyjifangon15/12/31.
*/
publicclassObjectPool{
privateMappool;
privateObjectPool(Mappool){
this.pool=pool;
}
privatestaticObjectgetInstance(StringclassName)throwsClassNotFoundException,IllegalAccessException,InstantiationException{
returnClass.forName(className).newInstance();
}
privatestaticJSONArraygetObjects(Stringconfig)throwsIOException{
Readerreader=newInputStreamReader(ClassLoader.getSystemResourceAsStream(config));
returnJSONObject.parseObject(CharStreams.toString(reader)).getJSONArray("objects");
}
//根据指定的JSON配置文件来初始化对象池
publicstaticObjectPoolinit(Stringconfig){
try{
JSONArrayobjects=getObjects(config);
ObjectPoolpool=newObjectPool(newHashMap());
if(objects!
=null&&objects.size()!
=0){
for(inti=0;iJSONObjectobject=objects.getJSONObject(i);
if(object==null||object.size()==0){
continue;
}
Stringid=object.getString("id");
StringclassName=object.getString("class");
pool.putObject(id,getInstance(className));
}
}
returnpool;
}catch(IOException|ClassNotFoundException|InstantiationException|IllegalAccessExceptione){
thrownewRuntimeException(e);
}
}
publicObjectgetObject(Stringid){
returnpool.get(id);
}
publicvoidputObject(Stringid,Objectobject){
pool.put(id,object);
}
publicvoidclear(){
pool.clear();
}
}
Client
publicclassClient{
@Test
publicvoidclient(){
ObjectPoolpool=ObjectPool.init("config.json");
Useruser=(User)pool.getObject("id1");
System.out.println(user);
Beanbean=(Bean)pool.getObject("id2");
System.out.println(bean);
}
}
User
publicclassUser{
privateintid;
privateStringname;
privateStringpassword;
publicintgetId(){
returnid;
}
publicvoidsetId(Integerid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetPassword(){
returnpassword;
}
publicvoidsetPassword(Stringpassword){
this.password=password;
}
@Override
publicStringtoString(){
return"User{"+
"id="+id+
",name='"+name+'/''+
",password='"+password+'/''+
'}';
}
}
Bean
publicclassBean{
privateBooleanusefull;
privateBigDecimalrate;
privateStringname;
publicBooleangetUsefull(){
returnusefull;
}
publicvoidsetUsefull(Booleanusefull){
this.usefull=usefull;
}
publicBigDecimalgetRate(){
returnrate;
}
publicvoidsetRate(BigDecimalrate){
this.rate=rate;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
@Override
publicStringtoString(){
return"Bean{"+
"usefull="+usefull+
",rate="+rate+
",name='"+name+'/''+
'}';
}
}
注意:
需要在pom.xml中添加如下依赖:
com.alibaba
fastjson
1.2.7
com.google.guava
guava
18.0
调用方法
当获取到某个类对应的Class对象之后,就可以通过该Class对象的getMethod来获取一个Method数组或Method对象.每个Method对象对应一个方法,在获得Method对象之后,就可以通过调用invoke方法来调用该Method对象对应的方法.
@CallerSensitive
publicObjectinvoke(Objectobj,Object...args)
throwsIllegalAccessException,IllegalArgumentException,
InvocationTargetException
{
...
}
下面我们对上面的对象池加强:
可以看到Client获取到的对象的成员变量全都是默认值,既然我们已经使用了JSON这么优秀的工具,我们又学习了动态调用对象的方法,那么我们就通过配置文件来给对象设置值(在对象创建时),新的配置文件形式如下:
{
"objects":
[
{
"id":
"id1",
"class":
"com.fq.domain.User",
"fields":
[
{
"name":
"id",
"value":
101
},
{
"name":
"name",
"value":
"feiqing"
},
{
"name":
"password",
"value":
"ICy5YqxZB1uWSwcVLSNLcA=="
}
]
},
{
"id":
"id2",
"class":
"com.fq.domain.Bean",
"fields":
[
{
"name":
"usefull",
"value":
true
},
{
"name":
"rate",
"value":
3.14
},
{
"name":
"name",
"value":
"bean-name"
}
]
},
{
"id":
"id3",
"class":
"com.fq.domain.ComplexBean",
"fields":
[
{
"name":
"name",
"value":
"complex-bean-name"
},
{
"name":
"refBean",
"ref":
"id2"
}
]
}
]
}
其中fields代表该Bean所包含的属性, name为属性名称, value为属性值(属性类型为JSON支持的类型), ref代表引用一个对象(也就是属性类型为Object,但是一定要引用一个已经存在了的对象)
/**
*@authorjifang
*@since15/12/31下午4:
00
*/
publicclassObjectPool{
privateMappool;
privateObjectPool(Mappool){
this.pool=pool;
}
privatestaticJSONArraygetObjects(Stringconfig)throwsIOException{
Readerreader=newInputStreamReader(ClassLoader.getSystemResourceAsStream(config));
returnJSONObject.parseObject(CharStreams.toString(reader)).getJSONArray("objects");
}
privatestaticObjectgetInstance(StringclassName,JSONArrayfields)
throwsClassNotFoundException,NoSuchMethodException,
IllegalAccessException,InstantiationException,InvocationTargetException{
//配置的Class
Class
>clazz=Class.forName(className);
//目标Class的实例对象
ObjecttargetObject=clazz.newInstance();
if(fields!
=null&&fields.size()!
=0){
for(inti=0;iJSONObjectfield=fields.getJSONObject(i);
//需要设置的成员变量名
StringfieldName=field.getString("name");
//需要设置的成员变量的值
ObjectfieldValue;
if(field.containsKey("value")){
fieldValue=field.get("value");
}elseif(field.containsKey("ref")){
StringrefBeanId=field.getString("ref");
fieldValue=OBJECTPOOL.getObject(refBeanId);
}else{
thrownewRuntimeException("neithervaluenorref");
}
StringsetterName="set"+
fieldName.substring(0,1).toUpperCase()+
fieldName.substring
(1);
//需要设置的成员变量的setter方法
MethodsetterMethod=clazz.getMethod(setterName,fieldValue.getClass());
//调用setter方法将值设置进去
setterMethod.invoke(targetObject,fieldValue);
}
}
returntargetObject;
}
privatestaticObjectPoolOBJECTPOOL;
//创建一个对象池的实例(保证是多线程安全的)
privatestaticvoidinitSingletonPool(){
if(OBJECTPOOL==null){
synchronized(ObjectPool.class){
if(OBJECTPOOL==null){
OBJECTPOOL=newObjectPool(newConcurrentHashMap());
}
}
}
}
//根据指定的JSON配置文件来初始化对象池
publicstaticObjectPoolinit(Stringconfig){
//初始化pool
initSingletonPool();
try{
JSONArrayobjects=getObjects(config);
for(inti=0;objects!
=null&&iJSONObjectobject=objects.getJSONObject(i);
if(object==null||object.size()==0){
continue;
}
Stringid=object.getString("id");
StringclassName=object.getString("class");
//初始化bean并放入池中
OBJECTPOOL.putObject(id,getInstance(className,object.getJSONArray("fields")));
}
returnOBJECTPOOL;
}catch(IOException|ClassNotFoundException|
InstantiationException|IllegalAccessException|
NoSuchMethodException|InvocationTargetExceptione){
thrownewRuntimeException(e);
}
}
publicObjectgetObject(Stringid){
returnpool.get(id);
}
publicvoidputObject(Stringid,Objectobject){
pool.put(id,object);
}
p