`
QING____
  • 浏览: 2235409 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA反射机制API简述

    博客分类:
  • JAVA
 
阅读更多

一.Annotation,java.lang.annotation.ElementType枚举

ElementType表示程序元素的类型,和@Target元注释类型一起使用,以指定在什么情况下使用注释类型合法的.

1)CONSTRUCTOR:构造方法声明

2)FIELD:字段声明

3)LOCAL_VARIABLE:局部变量声明

4)METHOD:方法声明

5)PACKAGE:包声明

6)PARAMETER:参数声明

7)TYPE:类/接口(包括注释)或者枚举声明.

8)ANNOTATION_TYPE:注释类型声明

 

二.RetentionPolicy枚举:

注释保留策略,他们与@Retention元注释类型一起使用,以指定保留注释的场景.

1)CLASS:编译器将把注释记录在类文件中,但在运行时VM不需要保留注释.

2)RUNTIME:编译器将把注释记录在类文件中,在运行时可以被VM保留,并可以被反射机制所获取.

3)SOURCE:注释只保留在原文件中.

 

@Documented:指定某一类型的注释将通过javadoc工具进行文档化.将成为API文档的一部分.

@Inherited:指定此注释类型可以被自动继承.如果注释类型声明中存在Inherited元注释,那么此元素将会自动继承父类/接口的注释类型.

@Retention:指定注释类型的注释保留策略,默认为RetentionPolicy.CLASS.

@Target:指示注释类型所适用的元素种类.如果注释类型声明中不存在Target元注释,则此注释可以被声明在任意元素类型上.Target允许指定多个ElementType作为其value.它和

ElementType枚举配合使用.

三.AnnotatedElement接口:

表示目前正在VM中运行的程序的一个已注释元素.该接口允许反射性的读取注释.

其中实现类有AccessibleObject(AccessibleObject子类有Constructor,Field,Method),Class和Package

方法列表:

 

1)public boolean isAnnotationPresent(Class<? extends Annotation> annotation):

如果指定的注释存在于此元素上,则返回true.

2)public Annotation[] getAnnotations():

返回此元素上存在的所有注释.如果没有注释,则返回长度为0的数组.

3)public Annotation getDeclaredAnnotation():

返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。

(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)

该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

 

四.Member接口:

成员是一种接口,反映有关单个成员(字段或方法)或者构造方法的标识信息.

其实现类有Constructor,Field,Method.

 

1) public Class<?> getDeclaringClass():

返回表示声明此Member表示的成员的Class对象,即此成员所属的原声明类对象.

2) public String getName():

返回此成员或者构造方法的简单命名.

3) public int getModifiers():

返回整数,表示此Member的修饰符信息.可以通过Modifier类的辅助方法来检测.

4) public boolean isSynthetic():

如果此成员是编译器引入的,则返回 true.

 

 

五.几种特殊的类型(Type接口的子接口)

GenericArrayType:泛型化数组类型.例如: <T> T[];

ParameterizedType:参数化类型.例如Collection<String>..方法列表:

WildcardType:表示一个通配符类型表达式,例如:?,? extends Number

 

六.AccessibleObject类

AccessibleObject类是Field,Method和Constructor对象的基类,它提供了将反射的对象标记为在使用时取消默认java语言访问控制检测的能力.对于公共成员/默认访问成员

/受保护成员和私有成员,在分别使用Filed/Method/Constructor对象来设置或者获取字段值/调用方法以获取执行结果时/创建或初始化类的新实例时,均会执行访问检测.

此类实现了AnnotatedElement接口.

 

1)public void setAccessible(boolean flag) throws SecurityException:

将对象的accessible标记设置为指定的值.如果值为true,则指示反射的对象在使用时应取消java语言的访问检测.

例如:private Date date;

此属性为private,如果在类的外部,是不能直接访问其值的.但是通过如下方式却可以.

DateTest test = new DateTest();

Field[] fields = test.getDeclareFields();

try{

for(Field f: fields){

f.setAccessible(true);

Date d = (Date)f.get(test);

System.out.print(d.toString());

}

}

七.Array类:

Array类提供了动态创建和访问java数据的能力.

1) static Object get(Object array,int index):

获取指定数组的相应索引的值.

2) static void set(Object array,int index,Object value):

设置数组的值.

3) static Object newInstance(Class<?> type,int length):

创建一个指定长度和数据类型的数组.

 

八.Constructor类:

Constructor提供了类的单个构造方法的信息以及对它的访问权限.

1) public T newInstance(Object...args):

使用此Constructor对象表示的构造方法来创建该构造方法声明类的实例.个别参数会自动解包,以匹配基本形参,必要时,基本参数和引用参数都要进行方法调用转换.如果构造器的参数列表为0,可以传递null或者空数组.

如果所需的访问检查和参数检查获得成功并且实例化继续进行,这是构造方法的声明类尚未初始化,则初始化此类.

会执行访问权限校验.如果setAccessible(true),那么在反射机制下,私有构造函数也可以创建实例.(打破单例设计的一个潜在可能)

 

九.Filed类:

提供了对类的成员属性进行操作的能力,以及对它的动态访问权限.反射的字段可能是一个类的静态字段或者实例字段.

1) public boolean isEnumConstant():

如果此字段表示枚举类型的元素,则返回true.

2) public Type getType():

返回一个Type对象,表示此Field对象所表示字段的声明类型.

3) public Object get(Object obj):

返回指定对象上此Field的值.如果该值为基本类型,将会被包装成类.

如果此属性为static,则忽略obj变量,即使obj为null.

此方法将会被安全访问权限检测.

4) public void set(Object obj,Object value) throws ..:

对obj对象上此属性进行赋值.

如果此属性为静态,则忽略obj值,即使obj为null.

此方法执行会被访问权限检测.

如果此属性为final,则抛出异常.

 

十.Method类:

此类提供了反射下访问类方法以及执行方法的能力,方法可以是static的.

 

1) public Class<?> getReturnType():

获取此方法的返回值类型.

2) public Type getGenericReturnType():

获取此方法的正式返回类型的type对象,Type可能是参数化type等.(泛型化返回结果)

3) public Class<?>[] getParameterTypes():

获得此方法的参数列表数组,如果无参,将返回尺寸为0的空数组.

4) public Object invoke(Object obj,Object...args) throws ...:

调用指定对象的此方法,并获得结果,此方法将会检测访问权限.(setAccessible(true)).如果底层方法是静态的,此时如果类没有实例化,则执行类初始化.如果方法是void类型,则返回null.

 

 

Class类可以获得所有对Constructor,Filed,Method列表的方法.这是类反射的引导类.

十一.Modifier类

Modifier类是一个辅助类,大量的静态方法,可以通过检测Member.getModifier()的值来获得成员的修饰符信息.

例如:Modifier.isAbstract(int)来检测成员是否为被abstract修饰.

 

十二.动态代理

InvocationHandler接口:代理实例的调用处理程序,每个代理实例(Proxy instance)都需要一个invocationHandler来执行调用时的代理过程.

此接口只有一个方法:

  • Object invoke(Object proxy,Method method,Object[] args) throws....

在代理实例上处理方法调用并返回结果;proxy参数为代理实例,Method为执行的方法,args为方法需要的参数列表.

 

Proxy类:动态代理:

静态代理即为代理类和实际类需要具有相同的接口列表,如果一个类需要有多种代理方式,就需要创建多个代理类,形成子类的数量巨多.动态代理类就避免了此问题,它允许在运行时指定需要代理的接口列表,动态创建代理实例.

可以通过如下方式获取代理实例:

Foo f = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},new FooInvocationHandler());

 

代理类(Proxy代理所创建的子类)具有如下属性:

1) 代理类为公共的/最终的/而不是抽象的.即不可被继承性.

2) 代理类扩展java.lang.reflect.Proxy.

3) 代理类会按同一顺序准确的实现其创建时指定的接口.

4) 对代理类class实例进行getInterfaces将返回一个包含相同接口列表的数组(按其创建时指定的顺序).

5) 可以通过Proxy.isProxyClass(Class proxy)来检测一个实例的类是否为代理类,通过Proxy.newInstance创建的类都是代理类.

6) 代理类是由底层字节码重构技术创建而来.代理类是一种特殊的存在于运行时的类.

 

代理实例proxy与实际类的类型匹配关系:

  • proxy instanceOf Foo将返回true.
  • (Foo)proxy强制类型转换成功.

 

对于代理类调用方法,将会指派到invocationHandler.invoke()方法上.

代理实例上的java.lang.Object中声明的hashCode,equals,toString方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,也将指派到invocationHandler.invoke上.即使是Object的方法调用,也会分配给handler执行.

 

////////////////////////////////////////////////ProxyDemo:

public class ProxyTestMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		DateOper oper = new DateOperImpl();
		DateOper proxyInstance = (DateOper)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{DateOper.class}, new Invocation(oper));
		proxyInstance.setDate(new Date());
		System.out.println(proxyInstance.getDate().getTime());
		System.out.println(proxyInstance.toString());
	}
	
	interface DateOper{
		public void setDate(Date date);
		
		public Date getDate();
	}
	
	static class DateOperImpl implements DateOper{
		
		private Date date;
		@Override
		public void setDate(Date date) {
			this.date = date;
			System.out.println("SetDate invoked!");
		}

		@Override
		public Date getDate() {
			System.out.println("GetDate invoked!");
			return date;
		}
		
		public String toString(){
			System.out.println("ToString invoked!");
			return super.toString();
		}
		
		public int hashCode(){
			System.out.println("HashCode invoked!");
			return super.hashCode();
		}
		
	}
	static class Invocation implements InvocationHandler{
		private Object obj;//被代理实例
		public Invocation(Object obj){
			this.obj = obj;
		}
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			System.out.println("proxy:" + proxy.getClass() + "//" + Proxy.isProxyClass(proxy.getClass()));
			System.out.println("method:" + method.getName());
			return method.invoke(obj, args);
		}
		
	}

}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics