《Effective Java》解读第41条:用标记接口定义类型

第41条:用标记接口定义类型

如果一个标记(例如注解或注释)是应用于一个类,并且会影响这个类在未来的行为或可操作性,那么最好将它定义为一个"标记接口",而不是一个"标记注解"。

简单来说,当你的标记有资格成为一个"类型"时,就应该使用接口。

标记接口

标记接口(Marker Interface) 是指没有任何方法声明,只是用来表明一个类拥有某种属性或能力的接口。

最经典的例子就是 java.io.Serializable:

java 复制代码
public interface Serializable {
    // 空空如也,没有定义任何方法
}

一个类实现了 Serializable,只是告诉JVM:"这个类的对象可以被序列化"。

标记接口与标记注解的使用

标记接口定义的类型是由被标记类的实例实现的;标记注解则没有定义这样的类型。

根本区别

  • 标记接口:实现了该接口的类,变成了该接口的子类型。这带来了编译期的类型检查优势。
  • 标记注解:注解只是给类打了个标签,它不会改变类的类型。

标记接口能在编译时捕获错误,而标记注解只能在运行时抛出异常。

标记接口可以被更精确地锁定

因为标记接口本身是一个类型,它可以成为其他API中泛型约束的一部分。

例如,你可以写一个 Set,确保这个集合里只能存放可序列化的对象。这是注解做不到的。

标记注解的优势

  1. 可以添加额外信息:注解可以通过添加元素,在标记的同时传递更多的元数据。例如,JPA中的 @Entity 注解可以附带 name 属性。

  2. 属于更大的注解体系:如果一个框架大量使用了注解(如Spring),那么在该框架内统一使用注解,比混合使用接口和注解更符合使用习惯。

案例

  • java.io.Serializable:必须用接口。因为 ObjectOutputStream.write(Object) 方法内部会检查对象是否是 Serializable 的实例,如果不是则抛出 NotSerializableException。这种检查依赖于类型系统。

  • java.lang.Override:必须用注解。因为它只用于方法,且仅仅作为编译器的辅助检查,本身不构成类型系统的一部分。

总结

如果你的标记是给别人用的"身份证"(类型),就用接口;如果你的标记是给自己看的"便利贴"(元数据),就用注解。

相关推荐
天空鸟_时光不老2 分钟前
13-亮点提炼:把技术说辞翻译成业务价值
java·spring boot·spring·spring cloud·mybatis
小蒜学长6 分钟前
基于SpringBoot+Vue的租房管理系统的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·租房管理
ZHOUPUYU6 分钟前
PHP 9.0 前瞻:下一代 PHP 会带来哪些新功能?
android·开发语言·php
某不知名網友7 分钟前
ROS2 核心通信:话题发布与订阅详解
开发语言·c++
C++ 老炮儿的技术栈8 分钟前
char (*csConnectName)[256]; 和 char csConnectName [256] 有什么区别
java·c语言·开发语言·c++·人工智能·算法·c
洋就在江州12 分钟前
gitlab-cicd 离线集成——springboot-cicd (非docker形式,shell形式)
java·spring boot·后端·ci/cd·gitlab·gitlab-runner
CEZ19 分钟前
JeeWMS 开源 WMS 全景导览:一套 Java 仓库管理系统从单据流到代码入口的阅读地图
java·开源
Nebula_g19 分钟前
JavaSE加强:线程Thread(线程安全重点)
java·开发语言·jvm·算法·javase·技术栈
令狐少侠201124 分钟前
centos7 下,使用docker 部署IOT 调试平台,ThingsBoard 并完美启动
java·spring boot·iot
小灰灰搞电子25 分钟前
Rust+Slint 实现一个终端软件源码分享(半成品)
开发语言·rust