首页 > 新闻动态 >  

新闻动态
NEWS

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
4interface ClassAnnotation
5 {
6 public String value();
7 }
8
9 @Target(ElementType.METHOD)
10 @Retention(RetentionPolicy.RUNTIME)
11 @Documented
12interface MethodAnnotation
13 {
14 public String methodName();
15 public String returnType();
16 }
17
18 @Target(ElementType.PARAMETER)
19 @Retention(RetentionPolicy.RUNTIME)
20 @Documented
21interface ParameterAnnotation
22 {
23 public String value();
24 }
25
26 @Target(ElementType.FIELD)
27 @Retention(RetentionPolicy.RUNTIME)
28 @Documented
29interface 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:


读取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 forint 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 }



读取Annotation体式格式二

 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 forint 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链接,可以看到:


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履行掉队行了阻碍,达到了我们期望的结果。

我所有的自负皆来自我的自卑,所有的英雄气概都来自于我的软弱。嘴里振振有词是因为心里满是怀疑,深情是因为痛恨自己无情。这世界没有一件事情是虚空而生的,站在光里,背后就会有阴影,这深夜里一片寂静,是因为你还没有听见声音。—— 马良《坦白书》
分享到: