The reason for writing this article stems from some technical discussions within the group. In fact, effective Java's item 37 has discussed marker Interface in detail. But from the whole item's point of view, it is in fact a positive attitude to the series of advantages and special features provided by marker interface. So a lot of people, including my colleagues, have taken some of the conclusions of the article as criteria for execution, ignoring the premise of getting these conclusions, and thus leading to some degree of misuse.
Of course, I'm not in opposition to effective Java's item 37. To tell you the truth, I don't have this capital either. It's just that I'm a bit more technically conservative, so hopefully this article will explain a series of problems that marker Interface might bring, and thus make it more prudent and accurate to use marker Interface.
Marker Interface Introduction
Perhaps some readers don't know what marker Interface is. So first let's look at the implementation of the set interface in the JDK:
1 Public Interface extends Collection<e> {2 }
Careful readers will find that, in fact, the set is more than collection without adding any interface functions. So why does the JDK define an additional interface for it?
I believe you will soon be able to answer: "This is because the data contained in the set does not have duplicate elements, and the collection interface is the root interface of the collection type interface, which does not add this restriction." ”
Yes. It is for this purpose that the JDK provides an additional set interface. And this interface, which does not add any new members, is actually marker Interface. And in the JDK, Marker interface a lot. Another very well-known marker interface is the Clonable interface:
1 Public Interface cloneable {2 }
Only this time, Marker interface received a different courtesy: whether in the prototype mode or in other daily discussions, it is used as a negative to explain what a bad design.
The positive and negative side of a coin
Is that marker interface good or bad? Without analysis, we would not have known why marker Interface was so different in different situations and would not know how to use marker Interface correctly. Therefore, we do not say the conclusion, but from the interface set and clonable two different cases to analyze the marker interface show the reasons for such differences.
Positive energy precedes. Let us first analyze the reason why this marker interface is performing well. When the user sees the set interface, the first thing he thinks about is that it is a collection, and that the collection has a nature that does not have duplicate elements. When the interface instance is manipulated, the software developer can manipulate it directly by invoking the individual member functions inherited by the set interface. The operations defined by these interfaces need to be defined by the implementation class of the set interface. So the nature of this non-existent duplicate element of set is actually guaranteed by the implementation class of the interface. As you add an element, we don't have to worry about whether the element is currently present in the collection:
1 set<item> itemset = ... 2 Itemset.add (item);
For other types of collections, such as list, we need to check that the element is already present in the collection, otherwise there will be a duplicate reference to the element inside it:
1 list<item> itemList = ... 2 if (! itemlist.contains (item)) {3 itemlist.add (item); 4 }
In turn, the other marker Interface clonable is notorious. The exact reason has already been made clear in item 17 in effective Java. In fact, the idea of creating the interface is consistent with the idea of creating a set interface: The interface is used to indicate that the type that implements the interface can be copied. One problem is that the clone () function of type object is protected. This makes it impossible for user code to invoke the Clone () function of the Clonable interface. This requires the user to implement the semantics represented by the Clonable interface in other ways. In turn, a lot of the following code is generated in the code:
1 if instanceof clonable) {2 ... 3 Else {4 ... 5 }
Thus, if an instance implements a specific interface, such as clonable, we will treat it in a special way. This is a situation in which marker interface is heavily misused by determining whether an instance implements a specific marker interface to determine the logic to process it. This code used for Marker interface actually destroys encapsulation: Marker interface instances cannot control how an external system uses an instance by means of a member function. In turn, the implementation of the type of marker interface is what is handled by the user code is determined. Marker interface, however, simply advises user code to manipulate it. That is, Marker interface has its user-related information, so it is logically coupled with the user in the current system, so that the type that implements the Marker interface cannot be reused in other systems.
And that's what effective Java's Item 37 emphasizes: Define a type by marker interface. We know that when defining a type, we don't just need to specify the data required to represent that type, but more importantly to abstract the interface for the type to manipulate that type. These interfaces specify how the type is operated, thereby isolating the type's internal implementation and user code. If we need to perform special processing outside of these interfaces by judging whether a particular type is specific, then it means that the type defined by the marker interface is semantically inappropriate.
And from the above to the set interface and Clonable interface comparison can be seen, if just like effective Java's item 371 by marker interface to define the type, There are two main ways to define types: derive from an interface so that marker interface has a special nature that is more than the parent interface. If marker interface does not have a parent interface, it should be a special property of the object class, and it can be manipulated by the various components provided by the object class, just like the serializable interface.
It is more common to derive from an interface to define marker interface, but it is also more prone to error. A more classic example is still to define an interface based on a rectangle for a square. Suppose a system already has an interface to represent a rectangle:
1 Public Interface Rectangle {2 void setwidth (double width); 3 void setheight (double height); 4 Double Getarea (); 5 }
Since a square is a special case where the length and width of a rectangle are equal, we often think of a square as a special rectangle. In this case, a software developer might decide to define a square by deriving from a rectangular interface:
1 Public Interface extends Rectangle {2 }
But in the process of use, he will be very uncomfortable to die. The reason for this is that the interface that is actually defined for the rectangle, such as SetWidth (), SetHeight (), is completely meaningless for the square. The square is required to be able to set its side length. So a proper definition of marker interface is the premise that each member of the original interface still has a definite meaning to the concept defined by marker interface.
OK, I believe that when you see the rectangle and square This example, the first thought is the Richter replacement principle (Liskov Substitution Principle). However, do not use the Richter replacement principle to determine whether a marker interface is appropriate. This is because the Richter substitution principle is actually used between objects: if S is a subtype of T, then the S object should be able to replace all T objects without altering any of the abstract properties. After all, whatever we create should be an instance of a type, but not an instance of the interface directly (except for anonymous classes).
For example, for a set interface, if we replace all use of the collection interface with the use of the set interface, then at least replacing the following statement causes the compiler to report a compilation error:
1 New Arraylist<item> ();
Therefore, it really does not make much sense to use the Richter substitution principle to determine whether a marker interface is appropriate, which is also discussed in StackOverflow.
Marker Interface vs. Annotation
As already mentioned in the previous chapters, Marker interface indicates that the type that implements the interface has a special nature. That is, Marker interface is an attribute of the type, that is, a metadata for that type. In Java, another Java component that can be used to represent type metadata is markup. In the case of similar problems, different classes of libraries have chosen different solutions. For example, serialization support in Java is actually done by serializable this marker interface:
1 Public classEmployeeImplementsjava.io.Serializable2 {3 PublicString name;4 PublicString address;5 Public transient intSSN;6 Public intNumber ;7}
In JPA, the control used to persist to the database is done through tags:
1 @Entity2@Table (name = "Employee")3 Public classEmployee {4@Column (name = "Name", unique =false, nullable =false, length = 40)5 PrivateString name;6 7@Column (name = "Address", unique =false, nullable =false, length = 200)8 PrivateString address;9 Ten@Column (name = "Number", unique =false, nullable =false) One Private intNumber ; A - @Transient - Private floatpercentageprocessed; the ...... -}
A question that follows is: Under what circumstances should we use marker Interface, and under what circumstances should we use the tag? Understanding when to use the premise is to understand the pros and cons of the two. Because the two are completely different syntax structures, the difference between them is very obvious:
First, start with marker interface. The advantage of this method is that by instanceof, it is possible to detect whether an instance is an instance of a particular interface, whereas a tag needs to be reflected to determine whether there are specific tokens on a particular instance. In addition to this reason, whether an interface is implemented on an instance can be checked at compile time, and whether an instance has a tag is not allowed at run time. When using instanceof, we are actually probing whether an instance is a type. Therefore, for marker interface, its first need to have certain practical significance.
The advantage of marking a marker interface is that it is finer in granularity. It can be said that the Marker interface can only be performed on the type, while the mark may be performed on a variety of types, so Marker interface is actually a consideration of the overall behavior, while the markers pay more attention to specific details. A well-defined fine-grained API can provide greater flexibility. And, compared to the interface, the tag's subsequent development ability is stronger, after all, adding a member function in an interface is a very troublesome thing.
In fact, a large part of the confusion between marker interface and tags is that the two are functionally repetitive, and the timing of the Java evolution is not the same, leading to the improper use of marker interface in some places. In fact, marker interface, such as Clonable, is a lot more in the JDK. One of the reasons why there are so many marker Interface in the JDK is that Java's support for markup is relatively late.
Reprint please specify the original address and marked reprint: http://www.cnblogs.com/loveis715/p/5094367.html
Commercial reprint please contact me in advance:[email protected]
Careful use of marker Interface