can marker interface like serializable contain def

2019-03-25 19:48发布

问题:

I think it can't, because marker interface principle is to not have any methods, but since default methods are not abstract I am not sure.

回答1:

A "Marker" interface is just a regular interface as far as Java is concerned. Thus, it can have default methods just as any (Java-8) interface can.

Now, as to whether this violates the principle of a Marker interface, I would have to say yes. A Marker interface should act as a flag of sorts, only identifying that a class meets some external criteria. Now, it can be a Marker interface and have abstract/default methods, but it will no longer purely meet the definition.

From Effective Java (Second Edition):

A marker interface is an interface that contains no method declarations, but merely designates (or “marks”) a class that implements the interface as having some property.



回答2:

A Marker Interface is a design pattern, so we can start to answer your question by observing just what the definition is:

In earlier versions of Java, Marker Interfaces were the only way to declare metadata about a class. For example, the Serializable Marker Interface lets the author of a class say that their class will behave correctly when serialized and deserialized.

The purpose of a Marker interface, in the context of Java, was to say something about that class. Funnily enough, it marked it as something. An example of this is the Serializable interface, that did nothing but marked that a Class was able to be serialized into a String. The question here is:

Does the definition include functionality?

No, I don't think it does. Functionality is more than just metadata about the class; it helps to define the class itself. It takes that step from metadata to data. So in terms of the design pattern, a marker interface can not define or declare functionality; it can simply make a statement about the implementing Class.



回答3:

A marker interface can have default methods, but having them is nonsensical.

A marker interface differs from a conventional interface in the way it's used. A conventional interface defines methods, both abstract and default. Thus it is sensible for a program to declare variables with that interface as its type, and to call methods of both kinds through a reference of that interface type.

A marker interface, by constrast, is not used for calling methods. It is a piece of meta-information about an object declared through the type system. It is typically used by calling code via an instanceof expression, or occasionally Class.isAssignableFrom(). It is pointless to declare a variable whose type is a marker interface, since there's nothing you can do with such a variable.

Examples of marker interfaces in the JDK are Cloneable, RandomAccess, and Serializable.

Now consider the addition of a default method to some marker interface:

interface Marker {
    default void foo() { ... }
}

What could the default implementation of foo do?

Implementations of default methods typically want to operate on this, and they do so by calling other instance methods on this. They could call other default methods, but having a bunch of default methods calling each other isn't useful. Eventually, some kind of actual operation on this must be performed. Since interface methods have no access to state (fields), any actual operations must be performed by abstract method implementations residing in an implementing class. However, in a marker interface there are no such methods.

The default implementation of foo could call a static method on this interface or on some other class. This is mostly pointless, as such a method would probably be better expressed as a static method in the first place. The implementation could pass this to a static method, but that method couldn't do anything useful with such a reference, since it has no methods! Well, it might have default methods, but now we're going in circles.

For a default method to be useful on an interface, that interface needs to have abstract methods as well. But if it has abstract methods, it's no longer a marker interface. Thus, it is nonsensical to have default methods on a marker interface.



回答4:

Although @Azar's answer is correct, we mustn't forget that Effective Java was written before default methods were introduced.

What is a marker interface?

There are two ways of looking at marker interfaces:

  1. They are interfaces that declare no methods.
  2. They are interfaces that don't force the implementation of any method.

The "official" definition is the first one but up until Java 7 those two statements were equivalent. It is a recurring pattern in Effective Java that once you publish an interface, you can't add any methods to it because it would force the implementation of the new methods.

However, this is exactly the problem default methods are trying to address: to allow for evolution of interfaces without the need to retrofit all classes implementing them. It also makes the two statements above mean slightly different things: a default method clearly violates statement 1 and by design doesn't violate statement 2.

What does all this mean in practice?

Imagine that you write an XML serialization engine and you create a marker interface XmlSerializable to go with it:

public interface XmlSerializable {}

So far, so good. But later on you realise that you actually have some classes that need special treatment, they need to provide their own custom converters. So what you may do is something like this:

public interface XmlSerializable {

   public static final Map<Class,Class> CONVERTERS = ...

   default Class customConverter() {
      return CONVERTERS.get(this.getClass());
   }
}

Would that stop XmlSerializable being a marker interface? You can say it still is a marker interface as you don't really add extra behaviour directly to your interface, only extra metadata that influences the behaviour of the serializer engine. On the other hand, this solution allows implementing classes to override customConverter(), which is slightly dodgy, a marker interface shouldn't allow that. (Then again, is Serializable and Cloneable relying on "magic" methods in the implementing class any better? I don't think so.)

Arguably the example above isn't a very good way to solve this kind of problem, you'd probably be much better off using annotations. But that also holds true for most "true" marker interfaces.

tl;dr

We can conclude that an interface with only default methods is more or less equivalent to an empty interface. If you want to make a theoretical distinction and not call it a marker interface, that is of course fine. But there's little practical difference, and given the inherent problems with marker interfaces in general, we should probably avoid them anyway.