[答案编辑] :简短的答案是我要执行的操作是不可能的。我的问题有点误导。我了解到Marker Interface模式实际上就是我在问题中所说的“标记注释”(因为您创建的注释实际上是一个接口)。并且只能在运行时进行检查。因此,如果您希望对带有批注的编译时进行检查,那是不可能的。空接口是唯一的选择。检查答案以了解如何在运行时执行此操作。
我试图避免使用标记界面,而使用标记注释。基本上,我希望一堆带有此批注的类,并将这些类的实例传递给接受该 type 的方法。这是我的代码:
标记注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Message {
}
CLASS:
@Message
public class MessageTypeA {
}
方法:
public class DatabaseWriter {
public void save(Message msg) {
//some code
}
}
呼叫代码:
MessageTypeA msgA = new MessageTypeA();
DatabaseWriter writer = new DatabaseWriter();
writer.save(msgA);
但是我得到Error:(78, 23) java: incompatible types: MessageTypeA cannot be converted to Message
我不确定自己在做什么,但是我读到可以用标记注释替换标记接口。在这种情况下不可能吗?
谢谢
答案 0 :(得分:0)
marker interface pattern是一种向运行时可读的程序类型或对象中添加元数据的方法。
例如,参见此模式的休眠实现。 Their insert
method接受普通的java.lang.Object
,并且在该方法中使用来自各种注释的元数据。
因此,按照您的示例实现,我将采用类似的方式
public class DatabaseWriter {
public void save(Object msg) {
if (msg.getClass().isAnnotationPresent(Message.class)) {
//some code
}
}
}
答案 1 :(得分:0)
在您的示例中,MessageTypeA
和Message
在类层次结构中不相关。仅当表达式的类型是形式参数类型的子类型时,方法调用才合法。
建立子类型关系的一种方法是使用接口,如您已经提到的。
建立子类型关系的另一种方法是使用类型限定符(表示为类型注释)。
类型质量等级:
@Message
|
@MessageTypeA
其中@MessageTypeA
是@Message
的子类型,而@Message
表示消息的未知类型。如果未编写任何类型注释,则默认为@Message
。
库
public class DatabaseWriter {
public void save(Object msg) {
// some code that can run on any old message
}
public void saveA(@MessageTypeA Object msg) {
// some code that is specific to MessageTypeA
}
}
客户
Object msg = ...;
@MessageTypeA Object msgA = ...;
DatabaseWriter writer = new DatabaseWriter();
writer.save(msg); // legal
writer.save(msgA); // legal
writer.saveA(msg); // compile-time error
writer.save(msgA); // legal
没有运行时开销或表示形式:强制执行是在编译时完成的。
Checker Framework是使您能够构建可强制使用正确的可插入类型检查器的工具。 (免责声明:我是该工具的维护者,但它是Amazon,Google,Uber等公司开发工具链的常规部分)。
您可以在几行代码中define your own type system。但是,仍然consider using Java subtypes rather than type qualifiers。