abstract methods in skeletal implementations of interfaces

I was re-reading Effective Java (2nd edition) item 18, prefer interfaces to abstract classes. In that item Josh Bloch provides an example of a skeletal implementation of the Map.Entry<K,V> interface:

// Skeletal Implementation
public abstract class AbstractMapEntry<K,V>
        implements Map.Entry<K,V> {
    // Primitive operations
    public abstract K getKey();
    public abstract V getValue();

 // ... remainder omitted
}

Two questions stem from this example:

  1. Why are getKey and getValue explicitly declared here as abstract methods? They are part of the Map.Entry interface, so I don't see a reason for the redundant declaration in the abstract class.
  2. Why use the idiom of leaving these primitives methods, as Mr. Bloch refers to them, as abstract? Why not just do this:

    // Skeletal Implementation public abstract class AbstractMapEntry implements Map.Entry { private K key; private V value;

        // Primitive operations
        public K getKey() {return key;}
        public V getValue() {return value;}
    
     // ... remainder omitted
    

    }

The benefits of this are that each subclass doesn't have to define its own set of fields, and can still access the key and value by their accessors. If a subclass truly needs to define its own behavior for the accessors, it can implement the Map.Entry interface directly. The other downside is that in the equals method provided by the skeletal implementation, the abstract accessors are called:

// Implements the general contract of Map.Entry.equals
@Override public boolean equals(Object o) {
    if (o == this)
        return true;
    if (! (o instanceof Map.Entry))
        return false;
    Map.Entry<?,?> arg = (Map.Entry) o;
    return equals(getKey(),   arg.getKey()) &&
           equals(getValue(), arg.getValue());
}

Bloch warns against calling overridable methods (item 17) from classes designed for inheritance as it leaves the superclass vulnerable to changes made by subclasses. Maybe this is a matter of opinion, but I was hoping to determine whether there's more to the story, as Bloch doesn't really elaborate on this in the book.


Asked by: Rafael973 | Posted: 28-01-2022






Answer 1

  1. I would say it helps emphasize what the concrete class is intended to deal with, instead of just leaving it up to the compiler to tell you (or you having to compare both to see what is missing). Kind of self-documenting code. But it certainly isn't necessary, it is more of a style thing, as far as I can see.
  2. There is more significant logic in returning these values than simple getter and setting. Every class I spot checked in the standard JDK(1.5) did something non-simple on at least one of the methods, so I would guess that he views such an implementation as too naive and it would encourage subclasses to use it instead of thinking through the problem on their own.

Regarding the issue with equals, nothing would change if the abstract class implemented them because the issue is overridable. In this case I would say that the equals is attempting to be carefully implemented to anticipate implementations. Normally equals in general should not be implemented to return true between itself and its subclass (although there are plenty that do) due to covariance issues (the superclass will think it equals the subclass, but the subclass won't think it equals the superclass), so this type of implementation of equals is tricky no matter what you do.

Answered by: Adelaide428 | Posted: 01-03-2022



Answer 2

Bloch warns against calling overridable methods (item 17) from classes designed for inheritance as it leaves the superclass vulnerable to changes made by subclasses

He warns about calling overridable methods in the constructor, not in other methods.

Answered by: Brooke662 | Posted: 01-03-2022



Answer 3

One reason that AbstractMapEntry#getKey and getValue are abstract (i.e. unimplemented) is that Map.Entry is an inner interface to Map. Using nested classes/interfaces is how Java implements composition. The idea in composition is that the composed part is not a first-class concept. Rather, the composed part only make sense if it is contained in the whole. In this case, the composed part is Map.Entry and the root object of the composite is Map. Obviously the concept expressed is that a Map has many Map.Entrys.

Therefore the semantics of AbstractMapEntry#getKey and getValue will depend essentially on the implementation of Map that we're talking about. A plain old getter implementation as you've written will work just fine for HashMap. It won't work for something like ConcurrentHashMap which demands thread-safety. It's likely that ConcurrentHashMap's implementation of getKey and getValue make defensive copies. (Recommend checking the source code for yourself).

Another reason not to implement getKey and getValue is that the characters that implement Map are radically different ranging from ones that should have never belonged (i.e. Properties) to completely different universes from an intuitive impls of Map (e.g. Provider, TabularDataSupport).

In conclusion, not implementing AbstractMapEntry#getKey and getValue, because of this golden rule of API design:

When in doubt, leave it out (see here)

Answered by: Miranda162 | Posted: 01-03-2022



Answer 4

  1. I don't see any reason

  2. Allows the implementation to define how the key and value are stored.

Answered by: Lily239 | Posted: 01-03-2022



Similar questions

Factory methods for implementations of Java interfaces wrapped with Scala implicits?

I'm using Scala implicits to define a rich wrapper for a Java interface: class RichThing { def richStuff: Unit = {} } In the companion object I define the implicit conversion and an apply factory method: object RichThing { implicit def rich( thing: JavaThing ) = new RichThing() def apply() = new RichThing() } With this, I can instant...


java - RMI: Does the client have to have all implementations or just interfaces?

Does client have to have all implementations or just interfaces? In details: let we have remote interface Foo: public interface Foo extends Remote { FooMessage getFooMessage () throws RemoteException; void setFooMessage (FooMessage fm) throws RemoteException; } Communication between client and server is happening by means of FooMessage. public interface FooM...


java - JMS interfaces and implementations

JMS API declare many General and concrete Interfaces (e.g., Connection vs. QueueConnection). It is documented that the best practice is to use the general interfaces (e.g. Session and not QueueSession). If my application is using both queues and topics and I'm going general, that is: Connection-->Session-->Topic/Queue, and suppose to support all JMS implementations (TiBCO, WebLogic, Websphere etc...) can I assume that usin...


oop - Why java interfaces can't contain static methods implementations?

I'm just curious, wouldn't it be more convinient to allow interfaces to contain implementations of static methods? Such methods could contain short commonly used(by this interface implementors) logic.


java - why are interfaces created instead of their implementations for every class

It seems to be the standard so I have been going along with it so far, but now I am building a new class from scratch instead of modifying the old ones and feel I should understand why I should follow the projects convention. Almost every class has an interface to it which is called classnameable. In the code database.class would never appear even once but in place where I would want to u...


Java packages for interfaces, abstract classes and implementations


java - How to use spring service interfaces and implementations in gwt by coding less?

i have a maven project having two modules; one spring module and one for gwt module. gwt module depends to spring module. And i have XService interfaces and XServiceImpl implementations as Spring beans annotated as @Service("myXServiceImpl"). I want to call myXServiceImpl bean's method from gwt client-side. For this purpose i write proper gwt classes; XGWTService, XGWTServiceAsync, XGWTServiceImpl and XGWTServiceIm...


java - How to create class that provides implementations of some interfaces

There is some interfaces in my app and I want to create singleton class, that provides implementations of them. Like so: public class Singleton{ //singleton's stuff private Interface1 interface1Impl; private Interface2 interface2Impl; public Interface1 getInterface1(){ return interface1Impl; } public Interface2 getInterface2(){ return interface2Impl; } }


java - What is the best approach for Unit testing when you have interfaces with both dummy & real implementations?

I'm familiar with the basic principles of TDD, being : Write tests, these will fail because of no implementation Write basic implementation to make tests pass Refactor code However, I'm a little confused as to where interfaces and implementation fit. I'm creating a Spring web application in my spare time, and rather than going in guns blazing, I'd like to understand how I can ...


java - How to use member variables with Interfaces and anonymous implementations

Please check the Java code below: public class Test { public static void main(String arg[]) throws Throwable { Test t = new Test(); System.out.println(t.meth().s); //OP: Old value System.out.println(t.meth().getVal()); //OP: String Implementation } private TestInter meth() { return new TestInter() { public String s = "String Implementation"; publi...


oop - Java implementations of the Prototype Pattern

What implementations of the Prototype Pattern exist on the Java platform? A prototype pattern is a creational design pattern used in software development when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects.


java - Where should you use BlockingQueue Implementations instead of Simple Queue Implementations?

I think I shall reframe my question from Where should you use BlockingQueue Implementations instead of Simple Queue Implementations ? to What are the advantages/disadvantages of BlockingQueue over Queue implementations taking into consideration aspects like speed,concurrency or other properties which vary e.g. time to access last element. I have used both kind of Queues. I...


java - Is it safe to assume that Spring MessageSource implementations are thread-safe?

Is it safe to assume that all implementations of org.springframework.context.MessageSource interface are thread-safe after initialization? I would expect that it's safe, but now I'm looking through Spring source code, and there's org.springframework.context.support.ReloadableResourceBundleMessageSource which reloads properties from time to time, and documentation doesn't say anything about being thread-safe... ...


Factory methods for implementations of Java interfaces wrapped with Scala implicits?

I'm using Scala implicits to define a rich wrapper for a Java interface: class RichThing { def richStuff: Unit = {} } In the companion object I define the implicit conversion and an apply factory method: object RichThing { implicit def rich( thing: JavaThing ) = new RichThing() def apply() = new RichThing() } With this, I can instant...


java - JPA Implementations - Which one is the best to use?


java - Compare JSF implementations


java - Differences between JVM implementations

Where do JVM Implementations differ (except licensing)? Does every JVM implement Type Erasure for the Generic handling? Where are the differences between: JRockit IBM JVM SUN JVM Open JDK Blackdown Kaffe ..... Deals one of them with Tail-Call-Optimization?


java - Any open source implementations of WS-DM working with JMX?

Closed. This question does not meet Stack Overflow guid...


Free C/C++ and Java implementations of PPP?

Are there free C/C++ and Java implementations of the point-to-point protocol (PPP) for use over a serial line? The C/C++ implementation will go into embedded hardware so portability is a concern. I'm not looking for a full TCP/IP stack, just something to provide a connection-oriented base to build on top of.


performance - Optimized implementations of java.util.Map and java.util.Set?

I am writing an application where memory, and to a lesser extent speed, are vital. I have found from profiling that I spend a great deal of time in Map and Set operations. While I look at ways to call these methods less, I am wondering whether anyone out there has written, or come across, implementations that significantly improve on access time or memory overhead? or at least, that can improve these things given some assu...






Still can't find your answer? Check out these amazing Java communities for help...



Java Reddit Community | Java Help Reddit Community | Dev.to Java Community | Java Discord | Java Programmers (Facebook) | Java developers (Facebook)



top