【问题标题】:Passing TYPE annotations to methods instead of marker interfaces将 TYPE 注释传递给方法而不是标记接口
【发布时间】:2019-06-29 18:23:57
【问题描述】:

[ANSWER EDIT]: 简短的回答是我想做的事情是不可能的。我的问题有点误导。我了解到Marker Interface 模式实际上就是我在问题中所说的标记注释(因为您创建的注释实际上是一个接口)。并且只能在运行时进行检查。因此,如果您希望很好地使用注释进行编译时检查,那是不可能的。空接口是唯一的选择。检查答案以了解如何在运行时执行此操作。


我试图避免使用标记接口来支持标记注释。基本上我想用这个注释标记一堆类,并将这些类的实例传递给接受该类型的方法。这是我的代码:

标记注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Message {
}

类:

@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

我不确定我正在做的事情是否可行,但我读到标记接口可以替换为标记注释。这种情况下不可以吗?

谢谢

【问题讨论】:

  • 你能提供一个更具体的代码示例吗?
  • @Aris_Kortex 已编辑
  • 为什么不能把Message做成接口并扩展MessageA?
  • 哦,我可以。但是在互联网上阅读时,它说这是一个标记接口(一个没有方法的接口)。并且这些可以用标记注释替换。我没有太多使用自定义注释,所以我什至不确定我想要做的事情是否可行。
  • 我建议你现在使用一个接口,因为以后你可以向它添加方法并强制实现。

标签: java interface annotations


【解决方案1】:

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
        }
    }
}

【讨论】:

  • 最初的问题以“我试图避免使用标记接口......”开头,所以这没有回答。
  • msg.getClass().isAnnotationPresent(Message.class)
【解决方案2】:

在您的示例中,MessageTypeAMessage 在类层次结构中不相关。仅当表达式的类型是形参类型的子类型时,方法调用才是合法的。

正如您已经指出的,建立子类型关系的一种方法是使用接口。

另一种建立子类型关系的方法是使用类型限定符(表示为类型注释)。

类型限定符层次结构:

   @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 是使您能够构建强制正确使用的可插入类型检查器的工具。 (免责声明:我是该工具的维护者,但它是亚马逊、谷歌、优步等开发工具链的常规部分。)

您可以在几行代码中define your own type system。不过,还是consider using Java subtypes rather than type qualifiers

【讨论】:

  • 不,这不起作用。试试看。我没有运行它,但绝对没有编译时错误
猜你喜欢
  • 2016-07-22
  • 2018-04-22
  • 1970-01-01
  • 2018-11-10
  • 1970-01-01
  • 1970-01-01
  • 2020-04-29
  • 2016-01-26
相关资源
最近更新 更多