当标记接口(如Serializable
)中没有要实现的内容时,实现它的用途是什么?
当标记接口(如Serializable
)中没有要实现的内容时,实现它的用途是什么?
约书亚·布洛赫:《Effective Java》第二版,179页
条款37:使用标记接口定义类型
... 有人会说标记注解(第35条)使标记接口过时了。这种说法是不正确的。标记接口比标记注解有两个优点。首先,标记接口定义了被标记类的一种类型;而标记注解则没有。这种类型的存在可以让你在编译时捕获到错误,在运行时如果你使用标记注解则只能等到运行时才知道错误...
就我个人而言,我认为我会顺从约书亚在这个主题上更加出色的知识。
writeObject(Serializable s)
。这种对标记接口的检查无法用注解来替代。 - Peter LawreySet
接口也不应该存在。它没有比 Collection
更多的方法,只是指定了契约。 - Malcolm这表示该类(以及所有非瞬态字段)都可以进行序列化。如果您正在构建一个依赖于序列化的框架,您当然可以编写以下方法:
public void registerObject(Serializable obj);
限制您准备接受的类。
由于序列化对象需要在系统之间保持兼容性,因此序列化是一种明确的设计决策,因此需要使用标记接口来识别这些候选项。
还有一个安全方面。您不希望使所有内容都可序列化-否则,您可能会通过序列化意外地公开(例如)密码或其他敏感数据。
Serializable
的情况下,将使用反射来序列化对象的字段。它们被称为“标记”接口。正如其名称所示,它们标记某些对象可用于特定类型的操作。
Serializable
表示该对象符合Java序列化规范。
有人讨论是否应该使用注解来取代它们,因为它们的功能非常相似。
如果您实现了一个接口,那么 instanceof
将会为真。如果您的接口没有任何需要实现的内容,那么可以使用它来为类打上元数据标记,就像Java 1.5及以上版本中的注释一样,而不必强制实现者进行任何特殊操作。
你的推理是正确的,一个空接口不会影响程序的“标准”执行,这个执行是基于字段的检查/变异和方法的分派。
然而,当与反射一起使用时,标记接口是有用的:一个库/方法通过反射检查一个对象,并且如果它的类实现了标记接口,则会以不同的方式工作。自Java5以来,很少需要标记接口 - 相同的“标记”功能可以通过Java注释实现 - 大多数效果都可以通过基于反射的代码实现。
我们通常会在需要检查类对象是否具有特定权限的场景中使用标记接口。我们使用 instanceOf
来检查权限。
public interface Herbivorous {
}
public interface Carnivorous {
}
public class Cow implements Herbivorous {
String howMuchGrassConsumed() {
return "2";
};
}
public class Lion implements Carnivorous {
String howManyCowsConsumed() {
return "2";
}
}
public class Jungle{
public static void main(String[] args) {
Cow cow = new Cow();
Lion lion = new Lion();
if(cow instanceof Herbivorous){
System.out.println("Cow ate so much gress:"+cow.howMuchGrassConsumed());
}else if(lion instanceof Carnivorous){
System.out.println("Lion ate so many cows:"+lion.howManyCowsConsumed(););
}else{
System.out.println("That's an alien");
}
}
}
主要目的是告诉编译器,对于实现了标记接口的类的对象进行不同的处理。