I am unable to come up with an explanation for why Java does not permit non-static nested interfaces. It makes a difference in the interaction between nested types and generics, since a non-static nested type would be implicitly generic from its enclosing type. The following uses a nested interface as a supertype of two nested classes, and seems to me to be a reasonable use of a non-static nested interface:
public class BSTMap0<K extends Comparable<K>, V> {
private interface Node {
Node put(K key, V value);
V get(K key);
}
private class NullNode implements Node {
public Node put(K key, V value) {
return new RealNode(key, value, this, this);
}
public V get(K key) { return null; }
}
private class RealNode implements Node {
// details omitted
}
private Node root;
public BSTMap0() { root = new NullNode(); }
public void put(K key, V value) { root = root.put(key, value); }
public V get(K key) { return root.get(key); }
}
This is not legal Java because the Node
interface is implicitly static and hence is not implicitly generic. There are two simple work-arounds. We could make the interface explicitly generic:
public class BSTMap1<K extends Comparable<K>, V> {
private interface Node<KK extends Comparable<KK>, VV> {
Node<KK,VV> put(KK key, VV value);
VV get(KK key);
}
private class NullNode implements Node<K, V> {
public Node<K,V> put(K key, V value) {
return new RealNode(key, value, this, this);
}
public V get(K key) { return null; }
}
// ... etc
This strikes me as unnecessarily verbose and ugly. Alternatively, we could make the interface be an abstract class with all abstract methods:
public class BSTMap2<K extends Comparable<K>,V> {
private abstract class Node {
abstract Node put(K key, V value);
abstract V get(K key);
}
private class NullNode extends Node {
public Node put(K key, V value) {
return new RealNode(key, value, this, this);
}
public V get(K key) { return null; }
}
// ... etc
I don't care for this because the Node
type exists only for polymorphism, not for implementation inheritance, and thus conceptually it's an interface, not an abstract class.
Can anyone give an explanation why Java disallows the first version, which to me seems like the right solution? A similar question was asked here a few years ago, but wasn't really answered. I'm hoping the example I gave will motivate the question better.
Edit: Since posting, I realized (as a comment below also pointed out) that this rule is older than generics in Java. Without generics there wouldn't be a need for a nested interface to be non-static, and once generics were introduced to Java presumably the rule would need to be preserved for backward compatibility (legacy classes exist that declare implicitly static nested interfaces which would suddenly become non-static if the rule were changed). To refine my question, is this rule only for backward compatibility, or is there an inherent reason for it that I'm missing?