黑马程序员_基础加强_关于反射的一些学习
2011-11-15 13:25
459 查看
----------------------android培训、java培训、期待与您交流!
----------------------
问题:
在运行时,对一个JAVA类,能否知道属性和方法;能否调用它的任意方法?
答案是可以的,JAVA提供一种反射机制可以实现。
一、什么是JAVA的反射机制
Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过ReflectionAPIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public,static等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。
Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。
换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
二、JDK中提供的ReflectionAPI
Java反射相关的API在包java.lang.reflect中,JDK1.6.0的reflect包如下图:
三、JAVA反射机制提供了什么功能
Java反射机制提供如下功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判段任意一个类所具有的成员变量和方法
在运行时调用任一个对象的方法
在运行时创建新类对象
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。
这里首先定义用于测试的类:
classType{
publicintpubIntField;
publicStringpubStringField;
privateintprvIntField;
publicType(){
Log("DefaultConstructor");
}
Type(intarg1,Stringarg2){
pubIntField=arg1;
pubStringField=arg2;
Log("Constructorwithparameters");
}
publicvoidsetIntField(intval){
this.prvIntField=val;
}
publicintgetIntField(){
returnprvIntField;
}
privatevoidLog(Stringmsg){
System.out.println("Type:"+msg);
}
}
classExtendTypeextendsType{
publicintpubIntExtendField;
publicStringpubStringExtendField;
privateintprvIntExtendField;
publicExtendType(){
Log("DefaultConstructor");
}
ExtendType(intarg1,Stringarg2){
pubIntExtendField=arg1;
pubStringExtendField=arg2;
Log("Constructorwithparameters");
}
publicvoidsetIntExtendField(intfield7){
this.prvIntExtendField=field7;
}
publicintgetIntExtendField(){
returnprvIntExtendField;
}
privatevoidLog(Stringmsg){
System.out.println("ExtendType:"+msg);
}
1、获取类的Class对象
Class类的实例表示正在运行的Java应用程序中的类和接口。获取类的Class对象有多种方式:
2、获取类的Fields
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。JAVA的Class<T>类提供了几个方法获取类的属性。
输出:
publicintcom.quincy.ExtendType.pubIntExtendField
publicjava.lang.Stringcom.quincy.ExtendType.pubStringExtendField
publicintcom.quincy.Type.pubIntField
publicjava.lang.Stringcom.quincy.Type.pubStringField
publicintcom.quincy.ExtendType.pubIntExtendField
publicjava.lang.Stringcom.quincy.ExtendType.pubStringExtendField
privateintcom.quincy.ExtendType.prvIntExtendField
可见getFields和getDeclaredFields区别:
getFields返回的是申明为public的属性,包括父类中定义,
getDeclaredFields返回的是指定类定义的所有定义的属性,不包括父类的。
3、获取类的Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法
Class<T>类提供了几个方法获取类的方法。
输出:
publicvoidcom.quincy.ExtendType.setIntExtendField(int)
publicintcom.quincy.ExtendType.getIntExtendField()
publicvoidcom.quincy.Type.setIntField(int)
publicintcom.quincy.Type.getIntField()
publicfinalnativevoidjava.lang.Object.wait(long)throwsjava.lang.InterruptedException
publicfinalvoidjava.lang.Object.wait()throwsjava.lang.InterruptedException
publicfinalvoidjava.lang.Object.wait(long,int)throwsjava.lang.InterruptedException
publicbooleanjava.lang.Object.equals(java.lang.Object)
publicjava.lang.Stringjava.lang.Object.toString()
publicnativeintjava.lang.Object.hashCode()
publicfinalnativejava.lang.Classjava.lang.Object.getClass()
publicfinalnativevoidjava.lang.Object.notify()
publicfinalnativevoidjava.lang.Object.notifyAll()
privatevoidcom.quincy.ExtendType.Log(java.lang.String)
publicvoidcom.quincy.ExtendType.setIntExtendField(int)
publicintcom.quincy.ExtendType.getIntExtendField()
4、获取类的Constructor
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例
Class<T>类提供了几个方法获取类的构造器。
5、新建类的实例
通过反射机制创建新类的实例,有几种方法可以创建
6、调用类的函数
通过反射获取类Method对象,调用Field的Invoke方法调用函数。
7、设置/获取类的属性值
通过反射获取类的Field对象,调用Field方法设置或获取值
四、动态创建代理类
代理模式:代理模式的作用=为其他对象提供一种代理以控制对这个对象的访问。
代理模式的角色:
抽象角色:声明真实对象和代理对象的共同接口
代理角色:代理角色内部包含有真实对象的引用,从而可以操作真实对象。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
动态代理:
动态Proxy是这样的一种类:
它是在运行生成的类,在生成时你必须提供一组Interface给它,然后该class就宣称它实现了这些interface。你可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口
步骤:
1、定义抽象角色
publicinterfaceSubject{
publicvoidRequest();
}
2、定义真实角色
publicclassRealSubjectimplementsSubject{
@Override
publicvoidRequest(){
//TODOAuto-generatedmethodstub
System.out.println("RealSubject");
}
}
3、定义代理角色
publicclassDynamicSubjectimplementsInvocationHandler{
privateObjectsub;
publicDynamicSubject(Objectobj){
this.sub=obj;
}
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
//TODOAuto-generatedmethodstub
System.out.println("Method:"+method+",Args:"+args);
method.invoke(sub,args);
returnnull;
}
}
4、通过Proxy.newProxyInstance构建代理对象
RealSubjectrealSub=newRealSubject();
InvocationHandlerhandler=newDynamicSubject(realSub);
Class<?>classType=handler.getClass();
Subjectsub=(Subject)Proxy.newProxyInstance(classType.getClassLoader(),
realSub.getClass().getInterfaces(),handler);
System.out.println(sub.getClass());
5、通过调用代理对象的方法去调用真实角色的方法。
sub.Request();
输出:
class$Proxy0新建的代理对象,它实现指定的接口
Method:publicabstractvoidDynamicProxy.Subject.Request(),Args:null
RealSubject调用的真实对象的方法
待续...
----------------------android培训、java培训、期待与您交流!
----------------------
----------------------
问题:
在运行时,对一个JAVA类,能否知道属性和方法;能否调用它的任意方法?
答案是可以的,JAVA提供一种反射机制可以实现。
一、什么是JAVA的反射机制
Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过ReflectionAPIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public,static等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。
Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。
换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
二、JDK中提供的ReflectionAPI
Java反射相关的API在包java.lang.reflect中,JDK1.6.0的reflect包如下图:
Member接口 | 该接口可以获取有关类成员(域或者方法)后者构造函数的信息。 |
AccessibleObject类 | 该类是域(field)对象、方法(method)对象、构造函数(constructor)对象的基础类。它提供了将反射的对象标记为在使用时取消默认Java语言访问控制检查的能力。 |
Array类 | 该类提供动态地生成和访问JAVA数组的方法。 |
Constructor类 | 提供一个类的构造函数的信息以及访问类的构造函数的接口。 |
Field类 | 提供一个类的域的信息以及访问类的域的接口。 |
Method类 | 提供一个类的方法的信息以及访问类的方法的接口。 |
Modifier类 | 提供了static方法和常量,对类和成员访问修饰符进行解码。 |
Proxy类 | 提供动态地生成代理类和类实例的静态方法。 |
Java反射机制提供如下功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判段任意一个类所具有的成员变量和方法
在运行时调用任一个对象的方法
在运行时创建新类对象
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。
这里首先定义用于测试的类:
classType{
publicintpubIntField;
publicStringpubStringField;
privateintprvIntField;
publicType(){
Log("DefaultConstructor");
}
Type(intarg1,Stringarg2){
pubIntField=arg1;
pubStringField=arg2;
Log("Constructorwithparameters");
}
publicvoidsetIntField(intval){
this.prvIntField=val;
}
publicintgetIntField(){
returnprvIntField;
}
privatevoidLog(Stringmsg){
System.out.println("Type:"+msg);
}
}
classExtendTypeextendsType{
publicintpubIntExtendField;
publicStringpubStringExtendField;
privateintprvIntExtendField;
publicExtendType(){
Log("DefaultConstructor");
}
ExtendType(intarg1,Stringarg2){
pubIntExtendField=arg1;
pubStringExtendField=arg2;
Log("Constructorwithparameters");
}
publicvoidsetIntExtendField(intfield7){
this.prvIntExtendField=field7;
}
publicintgetIntExtendField(){
returnprvIntExtendField;
}
privatevoidLog(Stringmsg){
System.out.println("ExtendType:"+msg);
}
1、获取类的Class对象
Class类的实例表示正在运行的Java应用程序中的类和接口。获取类的Class对象有多种方式:
调用getClass | Booleanvar1=true; Class<?>classType2=var1.getClass(); System.out.println(classType2); 输出:classjava.lang.Boolean |
运用.class语法 | Class<?>classType4=Boolean.class; System.out.println(classType4); 输出:classjava.lang.Boolean |
运用staticmethodClass.forName() | Class<?>classType5=Class.forName("java.lang.Boolean"); System.out.println(classType5); 输出:classjava.lang.Boolean |
运用primitivewrapperclasses的TYPE语法 这里返回的是原生类型,和Boolean.class返回的不同 | Class<?>classType3=Boolean.TYPE; System.out.println(classType3); 输出:boolean |
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。JAVA的Class<T>类提供了几个方法获取类的属性。
publicFieldgetField(Stringname) | 返回一个Field对象,它反映此Class对象所表示的类或接口的指定公共成员字段 |
publicField[]getFields() | 返回一个包含某些Field对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问公共字段 |
publicFieldgetDeclaredField(Stringname) | 返回一个Field对象,该对象反映此Class对象所表示的类或接口的指定已声明字段 |
publicField[]getDeclaredFields() | 返回Field对象的一个数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段 |
publicintcom.quincy.ExtendType.pubIntExtendField
publicjava.lang.Stringcom.quincy.ExtendType.pubStringExtendField
publicintcom.quincy.Type.pubIntField
publicjava.lang.Stringcom.quincy.Type.pubStringField
publicintcom.quincy.ExtendType.pubIntExtendField
publicjava.lang.Stringcom.quincy.ExtendType.pubStringExtendField
privateintcom.quincy.ExtendType.prvIntExtendField
可见getFields和getDeclaredFields区别:
getFields返回的是申明为public的属性,包括父类中定义,
getDeclaredFields返回的是指定类定义的所有定义的属性,不包括父类的。
3、获取类的Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法
Class<T>类提供了几个方法获取类的方法。
publicMethodgetMethod(Stringname,Class<?>...parameterTypes) | 返回一个Method对象,它反映此Class对象所表示的类或接口的指定公共成员方法 |
publicMethod[]getMethods() | 返回一个包含某些Method对象的数组,这些对象反映此Class对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共member方法 |
publicMethodgetDeclaredMethod(Stringname,Class<?>...parameterTypes) | 返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定已声明方法 |
publicMethod[]getDeclaredMethods() | 返回Method对象的一个数组,这些对象反映此Class对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法 |
Class<?>classType=ExtendType.class; //使用getFields获取属性 Field[]fields=classType.getFields(); for(Fieldf:fields) { System.out.println(f); } System.out.println(); //使用getDeclaredFields获取属性 fields=classType.getDeclaredFields(); for(Fieldf:fields) { System.out.println(f); }
输出:
publicvoidcom.quincy.ExtendType.setIntExtendField(int)
publicintcom.quincy.ExtendType.getIntExtendField()
publicvoidcom.quincy.Type.setIntField(int)
publicintcom.quincy.Type.getIntField()
publicfinalnativevoidjava.lang.Object.wait(long)throwsjava.lang.InterruptedException
publicfinalvoidjava.lang.Object.wait()throwsjava.lang.InterruptedException
publicfinalvoidjava.lang.Object.wait(long,int)throwsjava.lang.InterruptedException
publicbooleanjava.lang.Object.equals(java.lang.Object)
publicjava.lang.Stringjava.lang.Object.toString()
publicnativeintjava.lang.Object.hashCode()
publicfinalnativejava.lang.Classjava.lang.Object.getClass()
publicfinalnativevoidjava.lang.Object.notify()
publicfinalnativevoidjava.lang.Object.notifyAll()
privatevoidcom.quincy.ExtendType.Log(java.lang.String)
publicvoidcom.quincy.ExtendType.setIntExtendField(int)
publicintcom.quincy.ExtendType.getIntExtendField()
4、获取类的Constructor
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例
Class<T>类提供了几个方法获取类的构造器。
publicConstructor<T>getConstructor(Class<?>...parameterTypes) | 返回一个Constructor对象,它反映此Class对象所表示的类的指定公共构造方法 |
publicConstructor<?>[]getConstructors() | 返回一个包含某些Constructor对象的数组,这些对象反映此Class对象所表示的类的所有公共构造方法 |
publicConstructor<T>getDeclaredConstructor(Class<?>...parameterTypes) | 返回一个Constructor对象,该对象反映此Class对象所表示的类或接口的指定构造方法 |
publicConstructor<?>[]getDeclaredConstructors() | 返回Constructor对象的一个数组,这些对象反映此Class对象表示的类声明的所有构造方法。它们是公共、保护、默认(包)访问和私有构造方法 |
01 | //使用getConstructors获取构造器 |
02 | Constructor<?>[]constructors=classType.getConstructors(); |
03 | for (Constructor<?>m:constructors) |
04 | { |
05 | System.out.println(m); |
06 | } |
07 |
08 | System.out.println(); |
09 |
10 | //使用getDeclaredConstructors获取构造器 |
11 | constructors=classType.getDeclaredConstructors(); |
12 | for (Constructor<?>m:constructors) |
13 | { |
14 | System.out.println(m); |
15 | } |
16 |
17 | 输出: |
18 | public
|
19 |
20 | public
|
21 | com.quincy.ExtendType( int ,java.lang.String) |
通过反射机制创建新类的实例,有几种方法可以创建
调用无自变量ctor | 1、调用类的Class对象的newInstance方法,该方法会调用对象的默认构造器,如果没有默认构造器,会调用失败. Class<?>classType=ExtendType.class; Objectinst=classType.newInstance(); System.out.println(inst); 输出: Type:DefaultConstructor ExtendType:DefaultConstructor 2、调用默认Constructor对象的newInstance方法 Class<?>classType=ExtendType.class; Constructor<?>constructor1=classType.getConstructor(); Objectinst=constructor1.newInstance(); System.out.println(inst); 输出: Type:DefaultConstructor ExtendType:DefaultConstructor com.quincy.ExtendType@1006d75 |
调用带参数ctor | 3、调用带参数Constructor对象的newInstance方法 Constructor<?>constructor2= classType.getDeclaredConstructor(int.class,String.class); Objectinst=constructor2.newInstance(1,"123"); System.out.println(inst); 输出: Type:DefaultConstructor ExtendType:Constructorwithparameters com.quincy.ExtendType@15e83f9 |
通过反射获取类Method对象,调用Field的Invoke方法调用函数。
01 | Class<?>classType=ExtendType. class ; |
02 | Objectinst=classType.newInstance(); |
03 | MethodlogMethod=classType.<STRONG>getDeclaredMethod</STRONG>( "Log" ,String. class ); |
04 | logMethod.invoke(inst, "test" ); |
05 |
06 | 输出: |
07 | Type:DefaultConstructor |
08 | ExtendType:DefaultConstructor |
09 | <FONTcolor=#ff0000>Classcom.quincy.ClassTcannotaccessamemberof class com.quincy.ExtendTypewithmodifiers "private" </FONT> |
10 |
11 | <FONTcolor=#ff0000>上面失败是由于没有权限调用 private 函数,这里需要设置Accessible为 true ;</FONT> |
12 | Class<?>classType=ExtendType. class ; |
13 | Objectinst=classType.newInstance(); |
14 | MethodlogMethod=classType.getDeclaredMethod( "Log" ,String. class ); |
15 | <FONTcolor=#ff0000>logMethod.setAccessible( true );</FONT> |
16 | logMethod.invoke(inst, "test" ); |
通过反射获取类的Field对象,调用Field方法设置或获取值
1 | Class<?>classType=ExtendType. class ; |
2 | Objectinst=classType.newInstance(); |
3 | FieldintField=classType.getField( "pubIntExtendField" ); |
4 | intField.<STRONG>setInt</STRONG>(inst, 100 ); |
5 | int value=intField.<STRONG>getInt</STRONG>(inst); |
1 |
代理模式:代理模式的作用=为其他对象提供一种代理以控制对这个对象的访问。
代理模式的角色:
抽象角色:声明真实对象和代理对象的共同接口
代理角色:代理角色内部包含有真实对象的引用,从而可以操作真实对象。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
动态代理:
java.lang.reflect.Proxy | Proxy提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类 |
InvocationHandler | 是代理实例的调用处理程序实现的接口,每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的invoke方法。 |
它是在运行生成的类,在生成时你必须提供一组Interface给它,然后该class就宣称它实现了这些interface。你可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口
步骤:
1、定义抽象角色
publicinterfaceSubject{
publicvoidRequest();
}
2、定义真实角色
publicclassRealSubjectimplementsSubject{
@Override
publicvoidRequest(){
//TODOAuto-generatedmethodstub
System.out.println("RealSubject");
}
}
3、定义代理角色
publicclassDynamicSubjectimplementsInvocationHandler{
privateObjectsub;
publicDynamicSubject(Objectobj){
this.sub=obj;
}
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
//TODOAuto-generatedmethodstub
System.out.println("Method:"+method+",Args:"+args);
method.invoke(sub,args);
returnnull;
}
}
4、通过Proxy.newProxyInstance构建代理对象
RealSubjectrealSub=newRealSubject();
InvocationHandlerhandler=newDynamicSubject(realSub);
Class<?>classType=handler.getClass();
Subjectsub=(Subject)Proxy.newProxyInstance(classType.getClassLoader(),
realSub.getClass().getInterfaces(),handler);
System.out.println(sub.getClass());
5、通过调用代理对象的方法去调用真实角色的方法。
sub.Request();
输出:
class$Proxy0新建的代理对象,它实现指定的接口
Method:publicabstractvoidDynamicProxy.Subject.Request(),Args:null
RealSubject调用的真实对象的方法
待续...
----------------------
----------------------
相关文章推荐
- 黑马程序员__关于学习Java基础加强的总结_2
- 黑马程序员_学习日记43_609基础加强(多播委托、事件、程序集、反射)
- 黑马程序员java学习<基础加强>—反射
- 黑马程序员--Java基础加强--14.利用反射操作泛型III【解析关于泛型类型的细节信息的获取方法】【Method与泛型相关的方法】【个人总结】
- 黑马程序员--Java基础加强学习笔记之Class类、反射(Reflect)
- 黑马程序员_学习日记十五_基础加强之反射
- 黑马程序员__关于自己的一些学习死角的再学习(基于老毕的java基础视频)
- 黑马程序员__关于学习Java基础加强的总结_1
- 黑马程序员—Java基础加强学习笔记之枚举&反射
- 黑马程序员——基础加强——反射
- 黑马程序员_学习日记42_608基础加强(正则表达式、委托、匿名方法)
- 黑马程序员--Java基础加强--10.【PropertyDescriptor操作JavaBean VS 反射操作Java类】【个人总结】
- 黑马程序员_java基础学习笔记11_反射
- 黑马程序员 20 Java基础加强-02-反射篇
- 黑马程序员-JAVA基础加强-反射2
- 黑马程序员--Java基础加强学习笔记之重载和覆写、可变参数、枚举
- 黑马程序员: 基础加强(反射、类加载器、动态代理技术、AOP、InvocationHandler)
- 黑马程序员_java基础加强之(反射)
- 《黑马程序员》基础加强---数组和反射的应用
- 黑马程序员——基础加强---反射机制-认识Class类