Java中的标记接口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25850328/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Marker Interfaces in Java?
提问by Xavier DSouza
I was being taught that Marker interface in Java is an empty interface and is used to signal to compiler or JVM that the objects of the class implementing this interface must be treated in a special way, like serializing, cloning, etc.
我被告知 Java 中的 Marker 接口是一个空接口,用于向编译器或 JVM 发出信号,表明必须以特殊方式处理实现此接口的类的对象,例如序列化、克隆等。
But lately I have learned that it actually has nothing to do with the compiler or the JVM. For example, in case of Serializable
interface the method writeObject(Object)
of ObjectOutputStream
does something like instanceOf Serializable
to detect whether the class implements Serializable
& throws NotSerializableException
accordingly.
Everything is handled in the code and this seems to be a design-pattern so I think we can define our own marker interfaces.
但是最近我了解到它实际上与编译器或 JVM 无关。例如,在的情况下,Serializable
接口的方法writeObject(Object)
的ObjectOutputStream
不类似的东西instanceOf Serializable
,以检测类实现是否Serializable
与抛出NotSerializableException
相应。一切都在代码中处理,这似乎是一种设计模式,所以我认为我们可以定义我们自己的标记接口。
Now my doubts:
现在我的疑问:
Is the definition of a marker interface mentioned above in 1st point wrong? How can we define a Marker interface then?
And instead of using the
instanceOf
operator why can't the method be something likewriteObject(Serializable)
so that there is a compile-time type checking rather than runtime?How are Annotations better than Marker Interfaces?
上面第一点中提到的标记接口的定义是错误的吗?那么我们如何定义一个 Marker 接口呢?
而不是使用
instanceOf
运算符,为什么该方法不能像writeObject(Serializable)
这样有一个编译时类型检查而不是运行时?注释如何比标记接口更好?
采纳答案by dasblinkenlight
- Is the definition of a marker interface mentioned above in 1st point wrong?- It is correct in the parts that (1) a marker interface must be empty, and (2) implementing it is meant to imply some special treatment of the implementing class. The part that is incorrect is that it implies that JVM or the compiler would treat the objects of that class differently: you are correct in observing that it is the code of Java class library that treats these objects as cloneable, serializable, etc. It has nothing to do with the compiler or the JVM.
- instead of using the instanceOf operator why can't the method be something like
writeObject(Serializable)
so that there is a compile-time type checking- This lets you avoid polluting your code with the name of the marker interface when a "plainObject
" is needed. For example, if you make a class that needs to be serializable, and has object members, you would be forced to either do casting or make your objectsSerializable
at compile time. This is inconvenient, because the interface is devoid of any functionality. - How Annotations are better than Marker Interfaces?- They let you achieve the same purpose of conveying metadata about the class to its consumers without creating a separate type for it. Annotations are more powerful, too, letting programmers pass more sophisticated information to classes that "consume" it.
- 上面第一点中提到的标记接口的定义是错误的吗?- 在 (1) 标记接口必须为空的部分中是正确的,以及 (2) 实现它意味着对实现类进行一些特殊处理。不正确的部分是它暗示 JVM 或编译器会以不同的方式处理该类的对象:您正确地观察到 Java 类库的代码将这些对象视为可克隆、可序列化等。它有与编译器或 JVM 无关。
- 而不是使用 instanceOf 运算符,为什么该方法不能类似于
writeObject(Serializable)
这样,以便进行编译时类型检查- 这可以让您避免在需要“plainObject
”时使用标记接口的名称污染您的代码。例如,如果您创建一个需要可序列化并具有对象成员的类,您将被迫Serializable
在编译时进行强制转换或创建您的对象。这很不方便,因为界面没有任何功能。 - 注释如何比标记接口更好?- 它们使您可以达到将有关类的元数据传达给其使用者的相同目的,而无需为其创建单独的类型。注释也更强大,让程序员可以将更复杂的信息传递给“使用”它的类。
回答by Audrius Meskauskas
It is not possible to enforce Serializable
on writeObject
because children of non-serializable class can be serializable, but their instances may be upcasted back to the parent class. As a result, holding a reference to something non-serializable (like Object
) does not mean that the referred instance cannot be really serialized. For instance in
无法强制执行Serializable
,writeObject
因为不可序列化类的子类可以序列化,但它们的实例可能会向上转换回父类。因此,持有对不可序列化对象(如Object
)的引用并不意味着引用的实例不能真正序列化。例如在
Object x = "abc";
if (x instanceof Serializable) {
}
the parent class (Object
) is not serializable and would be initialised using its parameter-less constructor. The value referenced by x
, String
, is serializable and the conditional statement would run.
父类 ( Object
) 不可序列化,将使用其无参数构造函数进行初始化。通过引用的价值x
,String
是序列化的条件语句将运行。
回答by peter.petrov
It has nothing to do (necessarily) with the JVM and the compilers, it has something to do with any code which is interested in and is testing for a given marker interface.
It's a design decision and it's done for a good reason. See the answer from Audrius Me?kauskas.
With respect to this particular topic, I don't think it's a matter of being better or worse. The marker interface is doing what it's supposed to do just fine.
它与 JVM 和编译器无关(必然),它与任何对给定标记接口感兴趣并正在测试的代码有关。
这是一个设计决定,这样做是有充分理由的。请参阅 Audrius Me?kauskas 的回答。
关于这个特定的话题,我认为这不是变得更好或更坏的问题。标记界面正在做它应该做的事情。
回答by treeno
a. I have always seen them as a design pattern and nothing JVM-Special I have used that pattern in several situations.
一种。我一直将它们视为一种设计模式,并没有什么 JVM-Special 我在几种情况下都使用过这种模式。
c. I beleive that using Annotations to mark something is a better solution then using marker interfaces. Simply because Interfaces are in the first place aimed to define common interfaces of Types / Classes. They are part of the class-hierachy.
C。我相信使用注释来标记某些东西是比使用标记界面更好的解决方案。仅仅因为接口首先旨在定义类型/类的通用接口。它们是类层次结构的一部分。
Annotations are aimed to provide Meta-Informations to Code, and I think that marker are meta-informations. So they are exactly for that use-case.
注释旨在为代码提供元信息,我认为标记是元信息。所以它们完全适用于那个用例。
回答by Serge Ballesta
a/ A marker interface as its name suggest exists only to notify anything that knows about itthat a class declares something. The anything can be the JDK classes for the Serializable
interface, or any class you write yoursel for a custom one.
a/ 顾名思义,一个标记接口的存在只是为了通知任何知道它的人一个类声明了一些东西。任何东西都可以是Serializable
接口的 JDK 类,也可以是您为自定义类编写的任何类。
b/ If it is a marker interface, it should not imply the existence of any method - it would be better to include the implied method in the interface. But you can decide to design it as you want if you know whyyouneed it
b/ 如果是标记接口,不应该暗示任何方法的存在——最好在接口中包含隐含的方法。但是如果你知道你为什么需要它,你可以决定按照你想要的方式设计它
c/ There is little difference between an empty interface and an annotation that uses no value or parameter. But the difference is there : an annotation can declare a list of keys/values that will be accessible at run time.
c/ 空接口和不使用值或参数的注解几乎没有区别。但区别在于:注释可以声明在运行时可访问的键/值列表。
回答by MikeyB
I would argue first-off that Serializable and Cloneable are bad examples of marker interfaces. Sure, they're interfaces with methods, but they implymethods, such as writeObject(ObjectOutputStream)
. (The compiler will create a writeObject(ObjectOutputStream)
method for you if you don't override it, and all objects already have clone()
, but the compiler will again create a real clone()
method for you but with caveats. Both of these are weird edge cases that really aren't good design examples.)
我首先认为 Serializable 和 Cloneable 是标记接口的坏例子。当然,它们是与方法的接口,但它们隐含着方法,例如writeObject(ObjectOutputStream)
. (编译器会创建一个writeObject(ObjectOutputStream)
适合你的方法,如果你不重写,并且所有对象已经有了clone()
,但是编译器会再次创建一个真正的clone()
方法给你,但与告诫。这两者都是怪异的边缘的情况下,真正不好的设计示例。)
Marker interfaces are generally used for one of two purposes:
标记接口通常用于以下两个目的之一:
1) As a shortcut to avoid an excessively long type, which can happen with lots of generics. For instance, say you have this method signature:
1) 作为避免过长类型的捷径,这可能发生在许多泛型中。例如,假设你有这个方法签名:
public void doSomething(Foobar<String, Map<String, SomethingElse<Integer, Long>>>) { ... }
That's messy and annoying to type, and more importantly, difficult to understand. Consider this instead:
打字很麻烦也很烦人,更重要的是,很难理解。考虑一下:
public interface Widget extends Foobar<String, Map<String, SomethingElse<Integer, Long>>> { }
Then your method looks like this:
然后你的方法看起来像这样:
public void doSomething(Widget widget) { ... }
Not only is it clearer, but you can now Javadoc the Widget interface, and it's also easier to search for all occurrences in your code of Widget.
不仅更清晰,而且您现在可以 Javadoc Widget 界面,而且还可以更轻松地搜索您的 Widget 代码中的所有匹配项。
2) Marker interfaces can also be used as a way around Java's lack of intersection types. With a marker interface, you can require something to be of two different types, such as in a method signature. Say you have some interface Widget in your application, like we described above. If you have a method that requires a Widget that also happens to let you iterate over it (it's contrived, but work with me here), your only good solution is to create a marker interface that extends both interfaces:
2) 标记接口也可以用来解决 Java 缺乏交叉类型的问题。使用标记接口,您可以要求具有两种不同类型的东西,例如在方法签名中。假设您的应用程序中有一些界面 Widget,就像我们上面描述的那样。如果您有一个方法需要一个 Widget 并且恰好让您对其进行迭代(这是人为的,但在这里与我合作),您唯一好的解决方案是创建一个扩展两个接口的标记接口:
public interface IterableWidget extends Iterable<String>, Widget { }
And in your code:
在你的代码中:
public void doSomething(IterableWidget widget) {
for (String s : widget) { ... }
}
回答by vidya k n
A marker interface in Java is an interface with no fields or methods. Put more simply, an empty interface in Java is called a marker interface. Examples of marker interfaces are the
Serializable
,Cloneable
andRemote
interfaces. These are used to indicate some information to compilers or JVMs. So if the JVM sees that a class isSerializable
, it can do some special operation on it. Similarly, if the JVM sees some class is implementingCloneable
, it can perform some operations to support cloning. The same is true for RMI and theRemote
interface. So in short, a marker interface indicates a signal or a command to the compiler or JVM.
Java 中的标记接口是一个没有字段或方法的接口。更简单地说,Java 中的空接口称为标记接口。标记接口的示例是
Serializable
、Cloneable
和Remote
接口。这些用于向编译器或 JVM 指示一些信息。所以如果 JVM 看到一个类是Serializable
,它可以对它做一些特殊的操作。同样,如果 JVM 看到某个类正在实现Cloneable
,它可以执行一些操作来支持克隆。RMI 和Remote
接口也是如此。简而言之,标记接口向编译器或 JVM 指示信号或命令。
The above started out as a copy of a blog postbut has been lightly edited for grammar.
以上最初是博客文章的副本,但已针对语法进行了轻微编辑。
回答by infoj
The main purpose of marker interfaces is to create special types where types themselves have no behavior of their own.
标记接口的主要目的是创建特殊类型,其中类型本身没有自己的行为。
public interface MarkerEntity {
}
public boolean save(Object object) throws InvalidEntityFoundException {
if(!(object instanceof MarkerEntity)) {
throw new InvalidEntityFoundException("Invalid Entity Found, can't be saved);
}
return db.save(object);
}
Here save method makes sure that only the objects of classes that implement the MarkerEntity interface are saved, for other types InvalidEntityFoundException is thrown. So here MarkerEntity marker interface is defining a type that adds special behavior to the classes implementing it.
这里的 save 方法确保只保存实现 MarkerEntity 接口的类的对象,对于其他类型则抛出 InvalidEntityFoundException。所以这里 MarkerEntity 标记接口定义了一个类型,为实现它的类添加特殊行为。
Though annotations can also used now to mark classes for some special treatments but marker annotations are replacement for naming pattern not for Marker interfaces.
虽然现在也可以使用注解来标记一些特殊处理的类,但标记注解是替代命名模式而不是标记接口。
But marker annotations can't fully replace the marker interfaces because; marker interfaces are used to define type (as already explained above) where as marker annotations do not.
但是标记注释不能完全取代标记接口,因为;标记接口用于定义类型(如上所述),而标记注释则没有。
回答by yogesh kumar
If an interface does not contain any method and by implementing that interface if our object will get some ability such type of interfaces are called marker interfaces.
如果接口不包含任何方法并且通过实现该接口,如果我们的对象将获得某种能力,则此类接口称为标记接口。
回答by Shashank Bodkhe
I have made a simple demonstration to resolve doubt no 1 and 2 :
我做了一个简单的演示来解决疑问 1 和 2:
We will be having Movable interface which will be implemented by MobilePhone.java
Class and one more class LandlinePhone.java
which do NOTimplement Movable interface
我们将具有可调式界面,将通过实施MobilePhone.java
分类和多了一个类LandlinePhone.java
里面做不实现可移动的接口
Our marker Interface:
我们的标记界面:
package com;
public interface Movable {
}
LandLinePhone.java
and MobilePhone.java
LandLinePhone.java
和 MobilePhone.java
package com;
class LandLinePhone {
// more code here
}
class MobilePhone implements Movable {
// more code here
}
Our Custom Exception Class : package com;
我们的自定义异常类:package com;
public class NotMovableException extends Exception {
private static final long serialVersionUID = 1L;
@Override
public String getMessage() {
return "this object is not movable";
}
// more code here
}
Our Test class : TestMArkerInterface.java
我们的测试课: TestMArkerInterface.java
package com;
public class TestMarkerInterface {
public static void main(String[] args) throws NotMovableException {
MobilePhone mobilePhone = new MobilePhone();
LandLinePhone landLinePhone = new LandLinePhone();
TestMarkerInterface.goTravel(mobilePhone);
TestMarkerInterface.goTravel(landLinePhone);
}
public static void goTravel(Object o) throws NotMovableException {
if (!(o instanceof Movable)) {
System.out.println("you cannot use :" + o.getClass().getName() + " while travelling");
throw new NotMovableException();
}
System.out.println("you can use :" + o.getClass().getName() + " while travelling");
}}
Now when we execute main class :
现在当我们执行主类时:
you can use :com.MobilePhone while travelling
you cannot use :com.LandLinePhone while travelling
Exception in thread "main" com.NotMovableException: this object is not movable
at com.TestMarkerInterface.goTravel(TestMarkerInterface.java:22)
at com.TestMarkerInterface.main(TestMarkerInterface.java:14)
So which ever class implements marker interface Movable
will pass the test else error message will be displayed.
因此,实现标记接口的类Movable
将通过测试,否则将显示错误消息。
This is the way instanceOf
operator check is done for Serializable, Cloneableetc
这是instanceOf
对Serializable、Cloneable等进行操作员检查的方式