实施注释界面

对于Java开发人员来说,每天都需要使用注释。 如果没有别的,简单的@Override注释应该响起。 创建注释要复杂一些。 在运行时通过反射使用“自制”注释或创建编译时调用的注释处理器也是一种复杂性。 但是我们很少“实现”注释接口。 暗中有人暗地里为我们做。

当我们有注释时:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnoWithDefMethod {String value() default "default value string";
}

然后用这个注解注解的类

@AnnoWithDefMethod("my default value")
public class AnnotatedClass {
}

最后我们在运行时执行期间获取注释

AnnoWithDefMethod awdm = AnnotatedClass.class.getAnnotation(AnnoWithDefMethod.class);

那么我们如何进入变量awdm呢? 它是一个对象。 对象是类的实例,而不是接口。 这意味着Java运行时幕后的某个人“实现了”注释接口。 我们甚至可以打印出对象的特征:

System.out.println(awdm.value());System.out.println(Integer.toHexString(System.identityHashCode(awdm)));System.out.println(awdm.getClass());System.out.println(awdm.annotationType());for (Method m : awdm.getClass().getDeclaredMethods()) {System.out.println(m.getName());}

得到类似的结果

my default value
60e53b93
class com.sun.proxy.$Proxy1
interface AnnoWithDefMethod
value
equals
toString
hashCode
annotationType

因此,我们不需要实现注释接口,但是可以根据需要实现。 但是我们为什么要那样? 到目前为止,我遇到了一种解决方案:配置guice依赖项注入。

Guice是Google的DI容器。 绑定的配置以说明性方式作为Java代码提供,如文档页面中所述 。 您可以将类型绑定到实现,只需声明

bind(TransactionLog.class).to(DatabaseTransactionLog.class);

这样,所有注入的TransactionLog实例将属于DatabaseTransactionLog 。 如果要在代码的不同字段中注入不同的注入,则应以某种方式向Guice发出信号,例如创建注释,将注释放在字段或构造函数参数上并声明

bind(CreditCardProcessor.class).annotatedWith(PayPal.class).to(PayPalCreditCardProcessor.class);

这要求PayPal作为注释接口,并且您需要编写一个新的注释接口,以与每个CreditCardProcessor实现或更多实现相伴,以便您可以在绑定配置中用信号通知和分离实现类型。 仅有太多的注释类,这可能是一个过大的杀伤力。

除此之外,您还可以使用名称。 您可以使用注解@Named("CheckoutPorcessing")注释注入目标并配置绑定

bind(CreditCardProcessor.class).annotatedWith(Names.named("CheckoutProcessing")).to(CheckoutCreditCardProcessor.class);

这是众所周知的技术,已广泛用于DI容器中。 您指定类型(接口),创建实现,最后使用名称定义绑定类型。 这样做没有问题,只不过在键入处理而不是处理时很难注意到。 在绑定(运行时)失败之前,此类错误将一直隐藏。 您不能简单地使用final static String来保存实际值,因为它不能用作注释参数。 您可以在绑定定义中使用这样的常量字段,但是它仍然是重复的。

这个想法是使用其他东西代替String。 编译器检查的内容。 显而易见的选择是使用一个类。 为了实现可以从NamedImpl的代码学习而创建代码, NamedImpl是实现注释接口的类。 代码是这样的(注意: Klass是这里未列出的注释接口。):

class KlassImpl implements Klass {Class<? extends Annotation> annotationType() {return Klass.class}static Klass klass(Class value){return new KlassImpl(value: value)}public boolean equals(Object o) {if(!(o instanceof Klass)) {return false;}Klass other = (Klass)o;return this.value.equals(other.value());}public int hashCode() {return 127 * "value".hashCode() ^ value.hashCode();}Class value@OverrideClass value() {return value}
}

实际的绑定看起来像

@Injectpublic RealBillingService(@Klass(CheckoutProcessing.class) CreditCardProcessor processor,TransactionLog transactionLog) {...}bind(CreditCardProcessor.class).annotatedWith(Klass.klass(CheckoutProcessing.class)).to(CheckoutCreditCardProcessor.class);

在这种情况下,编译器很可能会发现任何错字。 实际发生在幕后的事情是什么,为什么我们要求实现注释接口?

配置绑定后,我们提供一个对象。 调用Klass.klass(CheckoutProcessing.class)将创建一个实例KlassImpl当吉斯试图决定是否实际绑定配置有效结合CheckoutCreditCardProcessorCreditCardProcessor论点的构造RealBillingService它只是调用该方法equals()上注释对象。 如果Java运行时创建的实例(请记住Java运行时创建的实例的名称类似于class com.sun.proxy.$Proxy1 ),并且我们提供的实例相等,那么将使用绑定配置,否则必须进行其他绑定比赛。

还有另一个问题。 实现equals()是不够的。 您可能(并且,如果您是Java程序员(这就是您为什么还要阅读这篇文章(您当然不是Lisp程序员)的原因),那么您也应该)记住,如果您覆盖equals()那么您还必须覆盖hashCode() 。 实际上,您应该提供一个与Java运行时创建的类进行相同计算的实现。 这样做的原因是,该比较可能不会直接由应用程序执行。 Guice可能(确实)正在从Map查找注释对象。 在那种情况下,哈希码用于标识比较对象必须位于其中的存储桶,然后使用equals()方法检查身份。 如果在创建Java运行时的情况下hashCode()方法返回的数字不同,则对象甚至无法匹配。 equals()将返回true,但不会为它们调用它,因为在映射中找不到该对象。

方法hashCode的实际算法在接口java.lang.annotation的文档中描述。 我以前看过此文档,但了解我第一次使用Guice并实现类似的注释接口实现类时定义算法的原因。

最后一件事是该类还必须实现annotationType() 。 为什么? 如果我知道了,我会写。

翻译自: https://www.javacodegeeks.com/2016/03/implementing-annotation-interface.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354856.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++入门经典-例2.13-左移运算

1&#xff1a;代码如下&#xff1a; // 2.13.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include<iostream> using namespace std; void main() {int a0x40,b;ba<<1;//左移1位cout << b << endl;//以十进制输出 } View Cod…

linux修改su的PAM配置文件,linux pam安全认证模块su命令的安全隐患

PAM安全认证1、su命令的安全隐患默认情况下&#xff0c;任何用户都允许使用su命令&#xff0c;从而有机会反复尝试其他用户(如root)的登录密码&#xff0c;带来安全风险。为了增强sum命令的使用控制&#xff0c;可以借助PAM认证模块&#xff0c;只允许极个别用户使用su命令进行…

jwebsocket传图片_Java中带有JWebSocket的WebServerSocket

jwebsocket传图片首先&#xff0c;转到http://jwebsocket.org/下载2个软件包Server and Client。 如果要查看源代码&#xff0c;请下载源代码包。 服务器 解压缩服务器程序包。 转到“ conf”文件夹 选择“ jWebSocket.xml”文件打开 编辑“ jWebSocket.xml”文件&#xff…

i3能装Linux虚拟机,使用i3wm重新安装Ubuntu

过去几天&#xff0c;我一直在Kubuntu 14.04.1 LTS(Ubuntu衍生产品)上使用i3wm&#xff0c;但体验有些不同。由于Ubuntu使用LightDM Display Manager&#xff0c;因此您可以安装i3wm并尝试与当前的窗口管理器一起使用。只需在外壳中使用以下命令安装适当的软件包&#xff1a;su…

99. 恢复二叉搜索树

99. 恢复二叉搜索树题意在BST中存在两个元素被交换了&#xff0c;现在需要把这两个元素给交换回来变成BST。解题思路将其转为数组&#xff0c;并且排好序后重新赋值给树结点&#xff1b;使用变量pre来保存访问的前一个结点&#xff0c;因为是中序遍历&#xff0c;所以前面一个结…

用Hamcrest验证DateTime和日期

自从我开始涉足自动化测试和练习TDD以来&#xff0c;验证日期值很痛苦。 幸运的是&#xff0c;这里有一个不错的库&#xff0c;可用于遗留Date和新的Java 8 DateTime API &#xff0c;从而解决了这一难题。 如果您属于Java开发社区中较健康的部分&#xff0c;并且每天练习单元…

linux找回rm的文件夹,Linux rm 文件恢复

Linux下删除命令 rm 大家肯定是熟悉得不能再熟悉了&#xff0c;然后有时候却阴沟里翻船不小心删除了某些重要的文件&#xff0c;想死的心都有了。。。。现在我们就来看看被误删除的文件要如何恢复&#xff1f;Linux文件系统Linux的文件系统(如ext3、ext4)由三部分组成&#xff…

linux xargs命令,xargs 命令教程

xargs是 Unix 系统的一个很有用的命令&#xff0c;但是常常被忽视&#xff0c;很多人不了解它的用法。本文介绍如何使用这个命令。一、标准输入与管道命令Unix 命令都带有参数&#xff0c;有些命令可以接受"标准输入"(stdin)作为参数。$ cat /etc/passwd | grep root…

java 职责链模式_Java中的责任链模式

java 职责链模式当应有几个处理器来执行某项操作并为这些处理器定义特定顺序时&#xff0c;就需要采用责任链设计模式。 在运行时处理器顺序的可变性也很重要。模式的UML表示如下&#xff1a; 处理程序定义处理器对象的一般结构。 这里的“ HandleRequest”是抽象处理器方法。 …

ArcMap 导入Excel坐标数据

1 准备Excel坐标数据集合 2 ArcMap加入Excel数据 将excel文件放入arcmap工作区的物理路径下在工作区的根图层上点键&#xff0c;选择添加数据&#xff0c;找到excel文件并选择相应的工作薄完成后&#xff0c;excel工作薄即导入工作区左边的图层下。3 ArcMap加入图层文件 在S…

linux6如何分区,CentOS6.9安装 硬盘分区方案与分区步骤

Linux默认可分为3个分区&#xff0c;分别是boot分区、swap分区和根分区&#xff1a;1、swap&#xff1a;交换分区&#xff0c;实现虚拟内存&#xff0c;建议大小是物理内存的1~2倍。2、/boot&#xff1a;用来存放与系统启动有关的程序&#xff0c;比如启动引导装载程序等&#…

实施自定义JMeter采样器

随着我们采用不同的体系结构和实现方式&#xff0c;对通用压力测试工具的需求不断增长。 Apache Jmeter是进行负载测试时最著名的工具之一。 它支持许多协议&#xff0c;例如ftp http tcp&#xff0c;并且可以轻松地用于分布式测试。 Jmeter还为您提供了一种创建自定义采样器…

hdu 6194 后缀数组

题意&#xff1a;一个字符串&#xff0c;查询恰好出现k次的子串的数目 思路&#xff1a;后缀数组在height上进行操作。我们直接枚举长度为k的区间求min值&#xff0c;但是要注意的是直接这么算是会重复的&#xff0c;同时也可能超过k次&#xff0c;这样我们就需要把枚举的前一个…

linux grep命令 例子,14个grep命令使用例子

所有的类linux系统都会提供一个名为grep(global regular expression print&#xff0c;全局正则表达式输出)的搜索工具。grep命令在对一个或多个文件的内容进行基于模式的搜索的情况下是非常有用的。模式可以是单个字符、多个字符、单个单词、或者是一个句子。当命令匹配到执行…

JSP动作元素

https://www.w3cschool.cn/jsp/jsp-actions.html JSP动作元素在请求处理阶段起作用。JSP动作元素是用XML语法写成的。 动作是第三种类型的语法元素&#xff0c;它们被转换成java代码来执行操作。如访问一个java对象或调用方法 利用JSP动作可以动态地插入文件、重用JavaBean组件…

c语言中的所有代码大全,C语言库函数代码大全

O类字母函数名: open 功 能:打开一个文件用于读或写 用 法: int open(char *pathname,int access[, int permiss]); 程序例: #include#include#include#include int main(void) { inthandle; char msg[] "Helloworld";if ((handle open("TEST.$$$", O_CRE…

依赖注入通俗解释_我如何向团队解释依赖注入

依赖注入通俗解释最近&#xff0c;我们公司开始开发一个新的基于Java的Web应用程序&#xff0c;经过一些评估过程&#xff0c;我们决定使用Spring。 但是许多团队成员并不了解Spring和Dependency Injection的原理。 因此&#xff0c;我被要求给出一个速成班&#xff0c;讲解什么…

session cookie

http://www.cnblogs.com/andy-zhou/p/5360107.html&#xff08;牛逼网址&#xff09; http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html&#xff08;同款牛逼&#xff09; cookie: session: Session是另一种记录客户状态的机制&#xff0c;不同的是Cookie保存…

C语言程序设计二期末考试,9第二学期期末考试《C语言程序设计》A

期末试题 二级c语言………………………………装………………………………订…………………………………线………………………………安徽工业大学题纸(一)2009~2010学年第一学期期末考试《C程序设计(2)》试卷 A考试时间&#xff1a;120分钟满分&#xff1a;100分(作题答案一律写…

SWT ScrolledComposite解释

就像我的一个朋友曾经说过的那样&#xff0c;SWT的ScrolledComposite是令人讨厌的野兽。 在某种程度上&#xff0c;我同意。 这可能是为什么有太多关于如何使用此小部件的问题的原因。 但不仅是ScrolledComposite的作者受到了谴责。 当某个软件无法按您预期的方式工作时&#…