Java回顾之反射
添加时间:2013-5-9 点击量:
第一篇:Java回顾之I/O
第二篇:Java回顾之收集通信
第三篇:Java回顾之多线程
第四篇:Java回顾之多线程同步
第五篇:Java回顾之凑集
第六篇:Java回顾之序列化
在这一篇文章里,我们存眷反射及其相干话题。
反射可以帮助我们查看指定类型中的信息、创建类型的实例,调用类型的办法。我们日常平凡应用框架,例如Spring、EJB、Hibernate等都多量的应用了反射技巧。
反射简单示例
下面来演示反射相干的根蒂根基操纵
起首是根蒂根基代码,我们定义一个接口及其实现,作为我们反射操纵的目标:
1 interface HelloWorldService
2 {
3 void sayHello(String name);
4 }
5
6 class MyHelloWorld implements HelloWorldService
7 {
8 public String name;
9
10
11 public void sayHello(String name)
12 {
13 System.out.println(Hello + name + .);
14 }
15
16 public void setName(String name) {
17 this.name = name;
18 }
19
20 public String getName() {
21 return name;
22 }
23 }
获取办法及字段信息
下面的代输出给定类型中的办法和字段的声明信息:
1 private static void printClassTypeInfo(String type) throws ClassNotFoundException
2 {
3 Class classType = Class.forName(type);
4 Method[] methods = classType.getDeclaredMethods();
5 System.out.println(Methods info as below:);
6 for(Method method : methods)
7 {
8 System.out.println(method.toGenericString());
9 }
10 Field[] fields = classType.getFields();
11 System.out.println(Fields info as below:);
12 for (Field field : fields)
13 {
14 System.out.println(field.toGenericString());
15 }
16 }
在应用反射时,我们一般会应用java.lang.reflect包中的内容。
然后我们调用下面的代码:
1 printClassTypeInfo(sample.reflection.MyHelloWorld);
输出成果如下:
Methods info as below:
public void sample.reflection.MyHelloWorld.sayHello(java.lang.String)
public java.lang.String sample.reflection.MyHelloWorld.getName()
public void sample.reflection.MyHelloWorld.setName(java.lang.String)
Fields info as below:
public java.lang.String sample.reflection.MyHelloWorld.name
实例化对象
我们可以应用class.netInstance的体式格式来创建一个对象,代码如下:
1 private static void createInstanceTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException
2 {
3 Class classType = Class.forName(sample.reflection.MyHelloWorld);
4 MyHelloWorld hello = (MyHelloWorld)classType.newInstance();
5 hello.sayHello(Zhang San);
6 }
输出成果:
Hello Zhang San.
调用对象的办法
我们可以经由过程办法的名称以及参数类型构建一个Method实例,然后调用Method的invoke办法,来触发办法。
示例代码如下:
1 private static void invokeMethodTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
2 {
3 Class classType = Class.forName(sample.reflection.MyHelloWorld);
4 MyHelloWorld hello = (MyHelloWorld)classType.newInstance();
5 Method method = classType.getMethod(sayHello, new Class[]{String.class});
6 method.invoke(hello, new Object[]{Zhang San});
7 }
输出成果同上。
批改字段的值
和C#不合,Java中一般应用setxxx和getxxx显示为属性赋值,是以Java中并没有Property类型,而是有Field类型。
我们可以对Field的值进行批改,代码如下:
1 private static void setFieldTest() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException
2 {
3 Class classType = Class.forName(sample.reflection.MyHelloWorld);
4 MyHelloWorld hello = (MyHelloWorld)classType.newInstance();
5 System.out.println(name is + hello.name);
6 Field field = classType.getField(name);
7 field.set(hello, Zhang San);
8 System.out.println(name is + hello.name);
9 }
履行成果如下:
name is null
name is Zhang San
可以看出,我们成功的批改了name的值。
Annotation摸索
一开端我们提到,反射是很多技巧的根蒂根基,Annotation就是如许的,我们可以把Annotation看做是C#中的Attribute,它可以对类型、办法、属性、字段、办法参数等信息进行润饰。我们可以应用“@+Annotation名”的体式格式来应用Annotation。
Annotation根蒂根基操纵
来看下面的代码,我们定义了基于Type、Method、Parameter和Field上方的Annotation示例:
1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @interface ClassAnnotation
5 {
6 public String value();
7 }
8
9 @Target(ElementType.METHOD)
10 @Retention(RetentionPolicy.RUNTIME)
11 @Documented
12 @interface MethodAnnotation
13 {
14 public String methodName();
15 public String returnType();
16 }
17
18 @Target(ElementType.PARAMETER)
19 @Retention(RetentionPolicy.RUNTIME)
20 @Documented
21 @interface ParameterAnnotation
22 {
23 public String value();
24 }
25
26 @Target(ElementType.FIELD)
27 @Retention(RetentionPolicy.RUNTIME)
28 @Documented
29 @interface FieldAnnotation
30 {
31 public String value();
32 }
接着,我们定义了一个MyClass类型,应用了上述的Annotation:
1 @ClassAnnotation(这是感化在类型上的Annotation)
2 class MyClass
3 {
4 @MethodAnnotation(methodName=printInfo, returnType=void)
5 public void printInfo(String info)
6 {
7 System.out.println(info);
8 }
9
10 @MethodAnnotation(methodName=printError, returnType=void)
11 public void printError(@ParameterAnnotation(这是感化在参数上的Annotation)String error)
12 {
13 System.err.println(error);
14 }
15
16 @FieldAnnotation(这是感化在字段上的Annotation)
17 public int count;
18 }
对于应用了Annotation,我们可以获取此中的信息,下面两种体式格式都可以获取Annotation,第一种体式格式是经由过程反射遍历类型及其办法、字段,一一读取Annotation信息;第二种体式格式是读取指定类型的Annotation:
1 private static void annotationTest1()
2 {
3 MyClass temp = new MyClass();
4
5 Annotation[] annotations = temp.getClass().getAnnotations();
6 for(Annotation a : annotations)
7 {
8 System.out.println(a.toString());
9 }
10
11 Method[] methods = temp.getClass().getDeclaredMethods();
12 for(Method method : methods)
13 {
14 annotations = method.getAnnotations();
15 for(Annotation a : annotations)
16 {
17 System.out.println(a.toString());
18 }
19 Annotation[][] paraAnnotations = method.getParameterAnnotations();
20 for(int i = 0; i < paraAnnotations.length; i++)
21 {
22 for (Annotation a : paraAnnotations[i])
23 {
24 System.out.println(a.toString());
25 }
26 }
27 }
28
29 Field[] fields = temp.getClass().getFields();
30 for (Field field : fields)
31 {
32 annotations = field.getAnnotations();
33 for(Annotation a : annotations)
34 {
35 System.out.println(a.toString());
36 }
37 }
38 }
1 private static void annotationTest2() throws ClassNotFoundException
2 {
3 Class classType = Class.forName(sample.reflection.annotation.MyClass);
4 boolean flag = classType.isAnnotationPresent(ClassAnnotation.class);
5 if (flag)
6 {
7 ClassAnnotation annotation = (ClassAnnotation) classType.getAnnotation(ClassAnnotation.class);
8 System.out.println(annotation.toString());
9 }
10 Method[] methods = classType.getMethods();
11 for(Method method : methods)
12 {
13 if (method.isAnnotationPresent(MethodAnnotation.class))
14 {
15 System.out.println(((MethodAnnotation)method.getAnnotation(MethodAnnotation.class)).toString());
16 }
17 Annotation[][] paraAnnotations = method.getParameterAnnotations();
18 for(int i = 0; i < paraAnnotations.length; i++)
19 {
20 for (Annotation a : paraAnnotations[i])
21 {
22 System.out.println(a.toString());
23 }
24 }
25 }
26 Field[] fields = classType.getFields();
27 for (Field field:fields)
28 {
29 if (field.isAnnotationPresent(FieldAnnotation.class))
30 {
31 System.out.println(((FieldAnnotation)field.getAnnotation(FieldAnnotation.class)).toString());
32 }
33 }
34 }
上述两个办法的输出都是一样的,如下:
@sample.reflection.annotation.ClassAnnotation(value=这是感化在类型上的Annotation)
@sample.reflection.annotation.MethodAnnotation(methodName=printInfo, returnType=void)
@sample.reflection.annotation.MethodAnnotation(methodName=printError, returnType=void)
@sample.reflection.annotation.ParameterAnnotation(value=这是感化在参数上的Annotation)
@sample.reflection.annotation.FieldAnnotation(value=这是感化在字段上的Annotation)
在WebService中应用Annotation
上述代码看上去可能有些呆板,不克不及显示出Annotation的威力,那么我们接下来看WebService,在WebService中,我们可以应用WebMethod、WebParam等Annotation来声明办法或者参数。
接下来,我们来实现一个很是简单的Web办事:
1 @WebService(targetNamespace=http://test, serviceName=HelloService)
2 public class HelloServiceProvider
3 {
4 @WebResult(name=HelloString)
5 @WebMethod
6 public String sayHello(@WebParam(name=userName) String name)
7 {
8 return Hello + name;
9 }
10
11 @Oneway
12 @WebMethod(action=userLogin, operationName=userLogin)
13 public void login()
14 {
15 System.out.println(User has logged on.);
16 }
17
18 public static void main(String[] args)
19 {
20 Thread thread = new Thread(new HelloServicePublisher());
21 thread.start();
22 }
23 }
然后定义一个Publisher:
1 class HelloServicePublisher implements Runnable
2 {
3 public void run()
4 {
5 Endpoint.publish(http://localhost:8888/test/HelloService, new HelloServiceProvider());
6 }
7 }
在号令行中,我们定位到源代码路径,履行下面的号令:
wsgen -cp . HelloServiceProvider
wsgen位于JDK的bin目次中。
然后我们启动HelloServiceProvider,在浏览器中输入如下地址:http://localhost:8888/test/HelloService,可以看到如下信息:
点击WSDL链接,可以看到:
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RIs version is JAX-WS RI 2.2.4-b01. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RIs version is JAX-WS RI 2.2.4-b01. --><definitions targetNamespace=http://test name=HelloService><types><xsd:schema><xsd:import namespace=http://test schemaLocation=http://localhost:8888/test/HelloService?xsd=1/></xsd:schema></types><message name=sayHello><part name=parameters element=tns:sayHello/></message><message name=sayHelloResponse><part name=parameters element=tns:sayHelloResponse/></message><message name=userLogin><part name=parameters element=tns:userLogin/></message><portType name=HelloServiceProvider><operation name=sayHello><input wsam:Action=http://test/HelloServiceProvider/sayHelloRequest message=tns:sayHello/><output wsam:Action=http://test/HelloServiceProvider/sayHelloResponse message=tns:sayHelloResponse/></operation><operation name=userLogin><input wsam:Action=userLogin message=tns:userLogin/></operation></portType><binding name=HelloServiceProviderPortBinding type=tns:HelloServiceProvider><soap:binding transport=http://schemas.xmlsoap.org/soap/http style=document/><operation name=sayHello><soap:operation soapAction=/><input><soap:body use=literal/></input><output><soap:body use=literal/></output></operation><operation name=userLogin><soap:operation soapAction=userLogin/><input><soap:body use=literal/></input></operation></binding><service name=HelloService><port name=HelloServiceProviderPort binding=tns:HelloServiceProviderPortBinding><soap:address location=http://localhost:8888/test/HelloService/></port></service></definitions>
JDK中自带了Web办事器,我们不须要把上述代码安排到其他办事器中。
机制
Spring中一大特点是AOP,面向方面编程也是框架设计一个趋势。对于营业中的共通操纵,诸如记录日记、保护事务等,若是和营业逻辑缠绕在一路,会造成代码职责不清,后续保护艰苦等题目。哄骗AOP,我们可以很好的分别共通操纵和营业操纵。
下面我们来实现一个简单的AOP框架,要实现如许一个框架,须要3项目组:1)InvocationHandler,来触发办法;2)Interceptor,来定义阻碍器;3)DynamicProxy,来动态创建对象。
起首我们看Interptor的定义:
1 interface AOPInterceptor
2 {
3 public void before(Method method, Object[] args);
4 public void after(Method method, Object[] args);
5 public void afterThrowing(Method method, Object[] args);
6 public void afterFinally(Method method, Object[] args);
7 }
接下来是InvocationHandler:
1 class DynamicProxyInvocationHandler implements InvocationHandler
2 {
3 private Object target;
4 private AOPInterceptor interceptor;
5
6 public DynamicProxyInvocationHandler(Object target, AOPInterceptor interceptor)
7 {
8 this.target = target;
9 this.interceptor = interceptor;
10 }
11
12 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
13 {
14 try
15 {
16 interceptor.before(method, args);
17 Object returnValue = method.invoke(target, args);
18 interceptor.after(method, args);
19 return returnValue;
20 }
21 catch(Throwable t)
22 {
23 interceptor.afterThrowing(method, args);
24 throw t;
25 }
26 finally
27 {
28 interceptor.afterFinally(method, args);
29 }
30 }
31 }
最后是DynamicProxy:
1 class DynamicProxyFactoryImpl implements DynamicProxyFactory
2 {
3 public <T> T createProxy(Class<T> clazz, T target, AOPInterceptor interceptor)
4 {
5 InvocationHandler handler = new DynamicProxyInvocationHandler(target, interceptor);
6 return (T)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {clazz}, handler);
7 }
8 }
至此,我们构建了一个”简略单纯“的AOP阻碍器。下面我们来创建一些测试代码。
起首是实现AOPInterceptor接口:
1 class MyInterceptor implements AOPInterceptor
2 {
3
4 public void after(Method method, Object[] args) {
5 System.out.println(办法履行停止。);
6 }
7
8 public void afterFinally(Method method, Object[] args) {
9 System.out.println(办法体Finally履行停止。);
10 }
11
12 public void afterThrowing(Method method, Object[] args) {
13 System.out.println(办法抛出异常。);
14 }
15
16 public void before(Method method, Object[] args) {
17 System.out.println(办法开端履行);
18 }
19 }
然后哄骗本文一开端定义的HelloWorldService,来完成测试,须要在MyHello的sayHello办法最后,追加一行代码:
1 throw new RuntimeException();
接着是测试代码:
1 private static void test()
2 {
3 MyInterceptor interceptor = new MyInterceptor();
4 HelloWorldService hello = new MyHelloWorld();
5 DynamicProxyFactory factory = new DynamicProxyFactoryImpl();
6 HelloWorldService proxy = factory.createProxy(HelloWorldService.class, hello, interceptor);
7 proxy.sayHello(Zhang San);
8 }
终极,履行成果如下:
办法开端履行
Hello Zhang San.
办法抛出异常。
办法体Finally履行停止。
Exception in thread main java.lang.reflect.UndeclaredThrowableException
at sample.reflection.dynamicproxy.¥Proxy0.sayHello(Unknown Source)
at sample.reflection.dynamicproxy.Sample.test(Sample.java:18)
at sample.reflection.dynamicproxy.Sample.main(Sample.java:9)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sample.reflection.dynamicproxy.DynamicProxyInvocationHandler.invoke(Sample.java:60)
... 3 more
可以看出,我们已经在营业履行的前、后、异常抛出后以及finally履行掉队行了阻碍,达到了我们期望的结果。
我所有的自负皆来自我的自卑,所有的英雄气概都来自于我的软弱。嘴里振振有词是因为心里满是怀疑,深情是因为痛恨自己无情。这世界没有一件事情是虚空而生的,站在光里,背后就会有阴影,这深夜里一片寂静,是因为你还没有听见声音。—— 马良《坦白书》