【反射】Java反射机制应用实践 喜欢ヅ旅行 2022-06-15 05:23 175阅读 0赞 ## 引言 ## Java反射机制是一个非常强大的功能,在很多大型项目比如Spring, Mybatis中都可以看见反射的身影。通过反射机制我们可以在运行期间获取对象的类型信息,利用这一特性我们可以实现工厂模式和代理模式等设计模式,同时也可以解决Java泛型擦除等令人苦恼的问题。本文我们就从实际应用的角度出发,来应用一下Java的反射机制。 ## 反射基础 ## p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没有接触过的话,建议先看一下官方文档的[Quick Start][]。 在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的反射类`Class`,在Java中我们有三种方法可以获取一个对象的反射类。 ### 通过getClass方法 ### 在Java中,每一个`Object`都有一个`getClass()`方法,通过getClass方法我们可以获取到这个对象对应的反射类: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> String s = <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"http://www.ziwenxie.site"</span>; </div> <div style="margin:0px; padding:0px; height:20px"> Class<?> c = s.getClass(); </div></pre> </td> </tr> </tbody> </table> ### 通过forName方法 ### 我们也可以调用`Class`类的静态方法`forName()`: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> Class<?> c = Class.forName( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"java.lang.String"</span>); </div></pre> </td> </tr> </tbody> </table> ### 使用.class ### 或者我们也可以直接使用`.class`: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> Class<?> c = String.class; </div></pre> </td> </tr> </tbody> </table> ## 获取类型信息 ## 在文章开头我们就提到反射的一大好处就是可以允许我们在运行期间获取对象的类型信息,下面我们通过一个例子来具体看一下。 首先我们在`typeinfo.interfacea`包下面新建一个接口`A`: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">package</span> typeinfo.interfacea; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">interface</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">A</span> </span>{ <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">f</span><span style="margin:0px; padding:0px">()</span></span>; } </div></pre> </td> </tr> </tbody> </table> 接着我们在`typeinfo.packageaccess`包下面新建一个类`C`,类`C`实现了接口`A`,并且我们还另外创建了几个用于测试的方法,注意下面几个方法的权限都是不同的。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">package</span> typeinfo.packageaccess; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">import</span> typeinfo.interfacea.A; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">C</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">implements</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">A</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">f</span><span style="margin:0px; padding:0px">()</span> </span>{ System.out.println( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"public C.f()"</span>); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">g</span><span style="margin:0px; padding:0px">()</span> </span>{ System.out.println( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"public C.g()"</span>); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">protected</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">v</span> <span style="margin:0px; padding:0px">()</span> </span>{ System.out.println( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"protected C.v()"</span>); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">u</span><span style="margin:0px; padding:0px">()</span> </span>{ System.out.println( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"package C.u()"</span>); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">w</span><span style="margin:0px; padding:0px">()</span> </span>{ System.out.println( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"private C.w()"</span>); } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">HiddenC</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> A <span style="margin:0px; padding:0px; color:rgb(38,139,210)">makeA</span><span style="margin:0px; padding:0px">()</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> C(); } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 在`callHiddenMethod()`方法中我们用到了几个新的API,其中`getDeclaredMethod()`根据方法名用于获取Class类指代对象自己声明的某个方法,然后我们通过调用`invoke()`方法就可以触发对象的相关方法: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">package</span> typeinfo; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">import</span> typeinfo.interfacea.A; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">import</span> typeinfo.packageaccess.HiddenC; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">import</span> java.lang.reflect.Method; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">HiddenImplementation</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">main</span><span style="margin:0px; padding:0px">(String[] args)</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">throws</span> Exception </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> A a = HiddenC.makeA(); </div> <div style="margin:0px; padding:0px; height:20px"> a.f(); </div> <div style="margin:0px; padding:0px; height:20px"> System.out.println(a.getClass().getName()); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// Oops! Reflection still allows us to call g():</span> </div> <div style="margin:0px; padding:0px; height:20px"> callHiddenMethod(a, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"g"</span>); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// And even methods that are less accessible!</span> </div> <div style="margin:0px; padding:0px; height:20px"> callHiddenMethod(a, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"u"</span>); </div> <div style="margin:0px; padding:0px; height:20px"> callHiddenMethod(a, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"v"</span>); </div> <div style="margin:0px; padding:0px; height:20px"> callHiddenMethod(a, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"w"</span>); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">callHiddenMethod</span><span style="margin:0px; padding:0px">(Object a, String methodName)</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">throws</span> Exception </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> Method g = a.getClass().getDeclaredMethod(methodName); </div> <div style="margin:0px; padding:0px; height:20px"> g.setAccessible( <span style="margin:0px; padding:0px; color:rgb(133,153,0)">true</span>); </div> <div style="margin:0px; padding:0px; height:20px"> g.invoke(a); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 从输出结果我们可以看出来,不管是`public`,`default`,`protect`还是`private`方法,通过反射类我们都可以自由调用。当然这里我们只是为了显示反射的强大威力,在实际开发中这种技巧还是不提倡。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> public C.f() </div> <div style="margin:0px; padding:0px; height:20px"> typeinfo.packageaccess.C </div> <div style="margin:0px; padding:0px; height:20px"> public C.g() </div> <div style="margin:0px; padding:0px; height:20px"> package C.u() </div> <div style="margin:0px; padding:0px; height:20px"> protected C.v() </div> <div style="margin:0px; padding:0px; height:20px"> private C.w() </div></pre> </td> </tr> </tbody> </table> 上面我们只是测试了`Method`对象,感兴趣的读者在熟悉了反射的API之后,不妨测试一下`Filed`,这里我们就不重复了。 ## 利用动态代理实现面向切面编程 ## AOP是Spring提供的一个强大特性之一,AOP的意思是面向切面编程,就是说要分离和业务不相关的代码,当我们需要新增相关的事务的时候,我们不想要对业务本身做修改。面向切面编程和面向对象变成相比到底有什么好处呢,我们通过一个例子来看一下,对于新手来说,常常会写出下面这样的代码: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Example1</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">execute</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 记录日志</span> </div> <div style="margin:0px; padding:0px; height:20px"> Logger logger = Logger.getLog(...); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 进行性能统计</span> </div> <div style="margin:0px; padding:0px; height:20px"> PerformanceUtil.startTimer(...); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 权限检查</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (!user.hasPrevilege()) { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 抛出异常</span> </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 执行真正的业务</span> </div> <div style="margin:0px; padding:0px; height:20px"> executeTransaction(); </div> <div style="margin:0px; padding:0px; height:20px"> PerformanceUtil.endTimer(); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 虽然我们上面真正要执行的业务只有`executeTransaction()`,但是日志,性能,权限相关的代码差不多要将真正的业务代码掩盖了。而且以后如果我们还有一个`Example2`,它同样需要实现相同的日志,性能,权限代码。这样当以后我们需要新增相关的逻辑检查的时候,我们需要所有`Example`进行重构,这显然不符合面向对象的一个基本原则-`封装变化`。 上面这个场景利用模板方法和装饰器模式都可以解决,在Spring中是通过动态代理来实现的,下面我们通过一个例子来模拟一下Spring中的AOP实现。 我们要实现的业务时,统计程序统计员工工资所执行的时间以及检查用户的权限。首先先来实现的`Salary`类,它里面包含一些实现统计员工工资的业务逻辑: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">interface</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">SalaryInterface</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">doSalary</span><span style="margin:0px; padding:0px">()</span></span>; </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Salary</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">implements</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">SalaryInterface</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">doSalary</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> ... </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 通过`InvocationHandler`我们来实现动态代理,以后当我们调用`obj`的相关方法之前,都会通过`invoke`方法进行代理,而不会直接调用`obj`方法。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">SimpleProxy</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">implements</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">InvocationHandler</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> Object obj; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> Object advice; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 绑定代理对象</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> Object <span style="margin:0px; padding:0px; color:rgb(38,139,210)">bind</span><span style="margin:0px; padding:0px">(Object obj, Advice advice)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">this</span>.obj = obj; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">this</span>.advice = advice; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> Proxy.newProxyInstance(obj.getClass().getClassLoader(), </div> <div style="margin:0px; padding:0px; height:20px"> obj.getClass().getInterfaces(), <span style="margin:0px; padding:0px; color:rgb(133,153,0)">this</span>) </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 实现代理</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> Object <span style="margin:0px; padding:0px; color:rgb(38,139,210)">invoke</span><span style="margin:0px; padding:0px">(Object proxy, Method method, Object[] args)</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">throws</span> Throwalbe </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> Object result = <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span>; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">try</span> { </div> <div style="margin:0px; padding:0px; height:20px"> advice.before(); </div> <div style="margin:0px; padding:0px; height:20px"> result = method.invoke(obj, args); </div> <div style="margin:0px; padding:0px; height:20px"> advice.after(); </div> <div style="margin:0px; padding:0px; height:20px"> } <span style="margin:0px; padding:0px; color:rgb(133,153,0)">catch</span>(Exception e) { </div> <div style="margin:0px; padding:0px; height:20px"> e.printStackTrace(); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> result </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 模拟`Spring`中的`Advice`接口: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">interface</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Advice</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">before</span><span style="margin:0px; padding:0px">()</span></span>; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">after</span><span style="margin:0px; padding:0px">()</span></span>; </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 实现`TimeAdvice`用于统计程序的执行时间: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">TimeAdvice</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">implements</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Advice</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">long</span> startTime; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">long</span> endTime; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@Override</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">before</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> startTime = System.nanoTime(); <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 获取开始时间</span> </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@Override</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">after</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> endTime = System.nanoTime(); <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// 获取结束时间</span> </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 客户端调用代码如下: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Client</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">main</span><span style="margin:0px; padding:0px">(String[] args)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> SimpleProxy = <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> SimpleProxy(); </div> <div style="margin:0px; padding:0px; height:20px"> SalaryInterface salaryInterface = </div> <div style="margin:0px; padding:0px; height:20px"> (SalaryInterface) simpleProxy.bind( <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> Salary(), <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> TimeAdvice()); </div> <div style="margin:0px; padding:0px; height:20px"> salaryInterface.doSalary(); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 如果我们现在需要新增权限控制,我们来实现`ControlAdvie`类: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">ControlAdvice</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">implements</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Advice</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@Override</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">before</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (...) { </div> <div style="margin:0px; padding:0px; height:20px"> ... </div> <div style="margin:0px; padding:0px; height:20px"> } <span style="margin:0px; padding:0px; color:rgb(133,153,0)">else</span> { </div> <div style="margin:0px; padding:0px; height:20px"> ... </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@Override</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">after</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> ... </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 而我们客户端的代码只需要改成`simpleProxy.bind(new Salary(), new ControlAdvie)`就行了,而`SimpleProxy`本身不需要做任何的修改。 ## 与注解相结合 ## 在单元测试框架比如`Junit`中反射机制也得到了广泛的应用,即通过注解的方式。下面我们简单地来了解一下如何通过反射机制来获取相关方法的注解信息,比如说我们有下面这样一个业务场景,当用户在修改自己密码的时候,为了保证密码的安全性,我们要求用户的新密码要满足一些条件,比如说至少要包含一个非数字字符,不能与以前的密码相同之类的条件等。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">import</span> java.lang.annotation.* </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@Target</span>(ElementType.METHOD) </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@Retention</span>(RetentionPolicy.RUNTIME) </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px">@interface</span> UserCase { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">id</span><span style="margin:0px; padding:0px">()</span></span>; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> String <span style="margin:0px; padding:0px; color:rgb(38,139,210)">description</span><span style="margin:0px; padding:0px">()</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">default</span> "no description"</span>; </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 下面是我们检测密码的工具类的实现: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">PasswordUtils</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@UserCase</span>(id= <span style="margin:0px; padding:0px; color:rgb(42,161,152)">47</span>, description= <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"Password must contain at least one numeric"</span>) </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">boolean</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">validatePassword</span><span style="margin:0px; padding:0px">(String password)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> (password.matches( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"\\w*\\d\\w*"</span>)); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@UserCase</span>(id= <span style="margin:0px; padding:0px; color:rgb(42,161,152)">48</span>) </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> String <span style="margin:0px; padding:0px; color:rgb(38,139,210)">encryptPassword</span><span style="margin:0px; padding:0px">(String password)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> StringBuilder(password).reverse().toString(); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@UserCase</span>(id= <span style="margin:0px; padding:0px; color:rgb(42,161,152)">49</span>, description= <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"New passwords can't equal previously used ones"</span>) </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">boolean</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">checkForNewPassword</span><span style="margin:0px; padding:0px">(List<String> prevPasswords, String password)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> !prevPasswords.contains(password); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 利用反射我们可以写出更加清晰的测试代码,其中`getDeclaredMethods()`方法可以获取相关对象自己声明的相关方法,而`getAnnotation()`则可以获取`Method`对象的指定注解。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">UseCaseTracker</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">trackUseCases</span><span style="margin:0px; padding:0px">(List<Integer> useCases, Class<?> cl)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">for</span>(Method m : cl.getDeclaredMethods()) { </div> <div style="margin:0px; padding:0px; height:20px"> UseCase uc = m.getAnnotation(UseCase.class); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span>(uc != <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span>) { </div> <div style="margin:0px; padding:0px; height:20px"> System.out.println( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"Found Use Case: "</span> + uc.id() + <span style="margin:0px; padding:0px; color:rgb(42,161,152)">" "</span> + uc.description()); </div> <div style="margin:0px; padding:0px; height:20px"> useCases.remove( <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> Integer(uc.id())); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">for</span>( <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> i : useCases) { </div> <div style="margin:0px; padding:0px; height:20px"> System.out.println( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"Warning: Missing use case-"</span> + i); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">main</span><span style="margin:0px; padding:0px">(String[] args)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> List<Integer> useCases = <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> ArrayList<Integer>(); </div> <div style="margin:0px; padding:0px; height:20px"> Collections.addAll(useCases, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">47</span>, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">48</span>, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">49</span>, <span style="margin:0px; padding:0px; color:rgb(42,161,152)">50</span>); </div> <div style="margin:0px; padding:0px; height:20px"> trackUseCases(userCases, PasswordUtils.class); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> ## 解决泛型擦除 ## 现在有下面这样一个业务场景,我们有一个泛型集合类`List<Class<? extends Pet>>`,我们需要统计出这个集合类中每种具体的`Pet`有多少个。由于Java的泛型擦除,注意类似`List<? extends Pet>`的做法肯定是不行的,因为编译器做了静态类型检查之后,到了运行期间JVM会将集合中的对象都视为`Pet`,但是并不会知道`Pet`代表的究竟是`Cat`还是`Dog`,所以到了运行期间对象的类型信息其实全部丢失了。p.s: 关于泛型擦除,我在[上一篇文章][Link 1]里面有详细解释,感兴趣的朋友可以看一看。 为了实现我们上面的例子,我们先来定义几个类: <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Pet</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">extends</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Individual</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Pet</span><span style="margin:0px; padding:0px">(String name)</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(name); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Pet</span><span style="margin:0px; padding:0px">()</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(); } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Cat</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">extends</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Pet</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Cat</span><span style="margin:0px; padding:0px">(String name)</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(name); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Cat</span><span style="margin:0px; padding:0px">()</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(); } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Dog</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">extends</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Pet</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Dog</span><span style="margin:0px; padding:0px">(String name)</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(name); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Dog</span><span style="margin:0px; padding:0px">()</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(); } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">EgyptianMau</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">extends</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Cat</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">EgyptianMau</span><span style="margin:0px; padding:0px">(String name)</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(name); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">EgyptianMau</span><span style="margin:0px; padding:0px">()</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(); } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Mutt</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">extends</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Dog</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Mutt</span><span style="margin:0px; padding:0px">(String name)</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(name); } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Mutt</span><span style="margin:0px; padding:0px">()</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">super</span>(); } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 上面的`Pet`类继承自`Individual`,`Individual`类的的实现稍微复杂一点,我们实现了`Comparable`接口,重新自定义了类的比较规则,如果不是很明白的话,也没有关系,我们已经将它抽象出来了,所以不理解实现原理也没有关系。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Individual</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">implements</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Comparable</span><<span style="margin:0px; padding:0px; color:rgb(181,137,0)">Individual</span>> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">long</span> counter = <span style="margin:0px; padding:0px; color:rgb(42,161,152)">0</span>; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">final</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">long</span> id = counter++; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> String name; <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// name is optional</span> </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Individual</span><span style="margin:0px; padding:0px">(String name)</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">this</span>.name = name; } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">Individual</span><span style="margin:0px; padding:0px">()</span> </span>{} </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> String <span style="margin:0px; padding:0px; color:rgb(38,139,210)">toString</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> getClass().getSimpleName() + (name == <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span> ? <span style="margin:0px; padding:0px; color:rgb(42,161,152)">""</span> : <span style="margin:0px; padding:0px; color:rgb(42,161,152)">" "</span> + name); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">long</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">id</span><span style="margin:0px; padding:0px">()</span> </span>{ <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> id; } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">boolean</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">equals</span><span style="margin:0px; padding:0px">(Object o)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> o <span style="margin:0px; padding:0px; color:rgb(133,153,0)">instanceof</span> Individual && id == ((Individual)o).id; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">hashCode</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> result = <span style="margin:0px; padding:0px; color:rgb(42,161,152)">17</span>; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (name != <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span>) { </div> <div style="margin:0px; padding:0px; height:20px"> result = <span style="margin:0px; padding:0px; color:rgb(42,161,152)">37</span> * result + name.hashCode(); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> result = <span style="margin:0px; padding:0px; color:rgb(42,161,152)">37</span> * result + ( <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span>) id; </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> result; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">compareTo</span><span style="margin:0px; padding:0px">(Individual arg)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// Compare by class name first:</span> </div> <div style="margin:0px; padding:0px; height:20px"> String first = getClass().getSimpleName(); </div> <div style="margin:0px; padding:0px; height:20px"> String argFirst = arg.getClass().getSimpleName(); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> firstCompare = first.compareTo(argFirst); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (firstCompare != <span style="margin:0px; padding:0px; color:rgb(42,161,152)">0</span>) { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> firstCompare; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (name != <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span> && arg.name != <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span>) { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> secendCompare = name.compareTo(arg.name); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (secendCompare != <span style="margin:0px; padding:0px; color:rgb(42,161,152)">0</span>) { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> secendCompare; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> (arg.id < id ? - <span style="margin:0px; padding:0px; color:rgb(42,161,152)">1</span> : (arg.id == id ? <span style="margin:0px; padding:0px; color:rgb(42,161,152)">0</span> : <span style="margin:0px; padding:0px; color:rgb(42,161,152)">1</span>)); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 下面创建了一个抽象类`PetCreator`,以后我们通过调用`arrayList()`方法便可以直接获取相关`Pet`类的集合。这里使用到了我们上面没有提及的`newInstance()`方法,它会返回Class类所真正指代的类的实例,这是什么意思呢?比如说声明`new Dog().getClass().newInstance()`和直接`new Dog()`是等价的。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">abstract</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">PetCreator</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> Random rand = <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> Random( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">47</span>); </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// The List of the different getTypes of Pet to create:</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">abstract</span> List<Class<? extends Pet>> getTypes(); </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> Pet <span style="margin:0px; padding:0px; color:rgb(38,139,210)">randomPet</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(147,161,161); font-style:italic">// Create one random Pet</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> n = rand.nextInt(getTypes().size()); </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">try</span> { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> getTypes().get(n).newInstance(); </div> <div style="margin:0px; padding:0px; height:20px"> } <span style="margin:0px; padding:0px; color:rgb(133,153,0)">catch</span> (InstantiationException e) { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">throw</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> RuntimeException(e); </div> <div style="margin:0px; padding:0px; height:20px"> } <span style="margin:0px; padding:0px; color:rgb(133,153,0)">catch</span> (IllegalAccessException e) { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">throw</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> RuntimeException(e); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> Pet[] createArray( <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> size) { </div> <div style="margin:0px; padding:0px; height:20px"> Pet[] result = <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> Pet[size]; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">for</span> ( <span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> i = <span style="margin:0px; padding:0px; color:rgb(42,161,152)">0</span>; i < size; i++) { </div> <div style="margin:0px; padding:0px; height:20px"> result[i] = randomPet(); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> result; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> ArrayList<Pet> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">arrayList</span><span style="margin:0px; padding:0px">(<span style="margin:0px; padding:0px; color:rgb(133,153,0)">int</span> size)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> ArrayList<Pet> result = <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> ArrayList<Pet>(); </div> <div style="margin:0px; padding:0px; height:20px"> Collections.addAll(result, createArray(size)); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> result; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 接下来我们来实现上面这一个抽象类,解释一下下面的代码,在下面的代码中,我们声明了两个集合类,`allTypes`和`types`,其中`allTypes`中包含了我们呢上面所声明的所有类,但是我们具体的类型实际上只有两种即`Mutt`和`EgypianMau`,所以我们真正需要`new`出来的宠物只是`types`中所包含的类型,以后我们通过调用`getTypes()`便可以得到`types`中所包含的所有类型。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">LiteralPetCreator</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">extends</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">PetCreator</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@SuppressWarnings</span>( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"unchecked"</span>) </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">final</span> List<Class<? extends Pet>> allTypes = Collections.unmodifiableList( </div> <div style="margin:0px; padding:0px; height:20px"> Arrays.asList(Pet.class, Dog.class, Cat.class, Mutt.class, EgyptianMau.class)); </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">static</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">final</span> List<Class<? extends Pet>> types = allTypes.subList( </div> <div style="margin:0px; padding:0px; height:20px"> allTypes.indexOf(Mutt.class), allTypes.size()); </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> List<Class<? extends Pet>> getTypes() { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> types; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> 总体的逻辑已经完成了,最后我们实现用来统计集合中相关`Pet`类个数的`TypeCounter`类。解释一下`isAssignalbeFrom()`方法,它可以判断一个反射类是某个反射类的子类或者间接子类。而`getSuperclass()`顾名思义就是得到某个反射类的父类了。 <table style="margin:0px; padding:0px; border-collapse:collapse; border-spacing:0px; empty-cells:show; border:1px solid rgb(226,226,226); width:770px"> <tbody style="margin:0px; padding:0px"> <tr style="margin:0px; padding:0px"> <td style="margin:0px; padding:8px 16px 8px 15px; border-width:1px; border-style:solid; border-color:rgb(226,226,226) rgb(226,226,226) rgb(226,226,226) rgb(255,255,255); color:rgb(102,102,102)"> <pre style="margin-top:0px; margin-bottom:0px; padding:0px; font-family:Monaco,Menlo,Consolas,'Courier New',monospace; border:none; overflow:auto; background:rgb(238,238,238)"> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">class</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">TypeCounter</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">extends</span> <span style="margin:0px; padding:0px; color:rgb(181,137,0)">HashMap</span><<span style="margin:0px; padding:0px; color:rgb(181,137,0)">Class</span><?>, <span style="margin:0px; padding:0px; color:rgb(181,137,0)">Integer</span>> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> Class<?> baseType; </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">TypeCounter</span><span style="margin:0px; padding:0px">(Class<?> baseType)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">this</span>.baseType = baseType; </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">count</span><span style="margin:0px; padding:0px">(Object obj)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> Class<?> type = obj.getClass(); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (!baseType.isAssignableFrom(type)) { </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">throw</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> RuntimeException( </div> <div style="margin:0px; padding:0px; height:20px"> obj + <span style="margin:0px; padding:0px; color:rgb(42,161,152)">" incorrect type "</span> + type + <span style="margin:0px; padding:0px; color:rgb(42,161,152)">", should be type or subtype of "</span> + baseType); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> countClass(type); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">private</span> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">void</span> <span style="margin:0px; padding:0px; color:rgb(38,139,210)">countClass</span><span style="margin:0px; padding:0px">(Class<?> type)</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> Integer quantity = get(type); </div> <div style="margin:0px; padding:0px; height:20px"> put(type, quantity == <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span> ? <span style="margin:0px; padding:0px; color:rgb(42,161,152)">1</span> : quantity + <span style="margin:0px; padding:0px; color:rgb(42,161,152)">1</span>); </div> <div style="margin:0px; padding:0px; height:20px"> Class<?> superClass = type.getSuperclass(); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">if</span> (superClass != <span style="margin:0px; padding:0px; color:rgb(133,153,0)">null</span> && baseType.isAssignableFrom(superClass)) { </div> <div style="margin:0px; padding:0px; height:20px"> countClass(superClass); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px">@Override</span> </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; color:rgb(133,153,0)">public</span> String <span style="margin:0px; padding:0px; color:rgb(38,139,210)">toString</span><span style="margin:0px; padding:0px">()</span> </span>{ </div> <div style="margin:0px; padding:0px; height:20px"> StringBuilder result = <span style="margin:0px; padding:0px; color:rgb(133,153,0)">new</span> StringBuilder( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"{"</span>); </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">for</span> (Map.Entry<Class<?>, Integer> pair : entrySet()) { </div> <div style="margin:0px; padding:0px; height:20px"> result.append(pair.getKey().getSimpleName()); </div> <div style="margin:0px; padding:0px; height:20px"> result.append( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"="</span>); </div> <div style="margin:0px; padding:0px; height:20px"> result.append(pair.getValue()); </div> <div style="margin:0px; padding:0px; height:20px"> result.append( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">", "</span>); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"></div> <div style="margin:0px; padding:0px; height:20px"> result.delete(result.length() - <span style="margin:0px; padding:0px; color:rgb(42,161,152)">2</span>, result.length()); </div> <div style="margin:0px; padding:0px; height:20px"> result.append( <span style="margin:0px; padding:0px; color:rgb(42,161,152)">"} "</span>); </div> <div style="margin:0px; padding:0px; height:20px"> <span style="margin:0px; padding:0px; color:rgb(133,153,0)">return</span> result.toString(); </div> <div style="margin:0px; padding:0px; height:20px"> } </div> <div style="margin:0px; padding:0px; height:20px"> } </div></pre> </td> </tr> </tbody> </table> [Quick Start]: https://docs.oracle.com/javase/tutorial/reflect/ [Link 1]: http://www.ziwenxie.site/2017/03/01/java-generic/
相关 Java反射机制理解与实践:实例分析反射API Java的反射机制是一种动态获取和操作类信息的技术。它允许程序在运行时查看对象,调用方法,甚至修改字段值。 以下是反射API的一些常用实例: 1. 获取类的信息: ```j 迷南。/ 2024年09月19日 12:09/ 0 赞/ 10 阅读
相关 Java反射机制应用实例 Java的反射机制允许我们在运行时检查类、方法和字段的信息。下面是一个简单的反射机制应用实例: 1. **创建对象**: 首先,我们有一个已经定义的类,比如一个简单的"Per ╰+攻爆jí腚メ/ 2024年09月16日 19:45/ 0 赞/ 13 阅读
相关 Java反射机制应用示例 Java反射机制是Java语言提供的一种能力,允许程序在运行时检查类、字段、方法等信息,并动态调用它们。 以下是一个简单的反射机制应用示例: ```java // 创建一个 小灰灰/ 2024年09月12日 19:03/ 0 赞/ 23 阅读
相关 Java反射机制应用示例 在Java中,反射机制是一种强大的工具,它允许我们在运行时获取类、方法和变量的信息,并可以调用这些方法。 以下是一个简单的反射机制应用示例: ```java import ╰+哭是因爲堅強的太久メ/ 2024年09月11日 11:03/ 0 赞/ 22 阅读
相关 java反射机制详解及应用 1.如何创建Class的实例(反射的源头) 理解: Class是一个对象,对应一个运行时类。相当于一个运行时类本身充当了Class的一个实例 过程: 源文件经过编译(j 亦凉/ 2022年08月23日 03:52/ 0 赞/ 168 阅读
相关 反射机制及其应用 一个类 有组多个组成部分,例如成员变量,方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分。反射常常用于框架。 加载类 ![这里写图片描述][2016100909 「爱情、让人受尽委屈。」/ 2022年07月16日 06:45/ 0 赞/ 147 阅读
相关 JAVA反射机制的简单应用 开发的时候有时候会碰到这样的情况,我们在写程序的时候并不知道需要调用某个对象的哪个方法,只有程序运行后,我们才能够知道。或许我们需要根据客户端传过来的某个Strin 缺乏、安全感/ 2022年07月12日 10:57/ 0 赞/ 139 阅读
相关 JAVA反射机制的简单应用 开发的时候有时候会碰到这样的情况,我们在写程序的时候并不知道需要调用某个对象的哪个方法,只有程序运行后,我们才能够知道。或许我们需要根据客户端传过来的某个Strin 落日映苍穹つ/ 2022年07月12日 10:57/ 0 赞/ 165 阅读
相关 【反射】Java反射机制应用实践 引言 Java反射机制是一个非常强大的功能,在很多大型项目比如Spring, Mybatis中都可以看见反射的身影。通过反射机制我们可以在运行期间获取对象的类型信息,利用 喜欢ヅ旅行/ 2022年06月15日 05:23/ 0 赞/ 176 阅读
还没有评论,来说两句吧...