The examples in the linked article are a bit contrived and artificial (as already indicated by the odd names, A
, B
etc...). However, let's focus on the part of the quote that your question refers to:
"...without adding any type information (that is, without allowing any upcasting)."
The class may offer multiple (public or private) implementations of this interface. But the key point is:
Nobody will ever be able to figure out that they implement this interface.
Simply, because the interface is not public.
I tried to create an example showing a possible application case. Of course, it is still contrived, but may make the point more obvious. Consider you want to model a Tree
data structure, which consists of Node
objects. These can be InnerNode
objects (which have child nodes) or LeafNode
objects (which have no children).
Such a class could be implemented like this:
class Tree {
// The private interface
private interface Node {
List<Node> getChildren();
}
// Both are public implementations
public class InnerNode implements Node {
@Override
public List<Node> getChildren() {
return Arrays.<Node>asList(getLeafNode(), getLeafNode());
}
}
public class LeafNode implements Node {
@Override
public List<Node> getChildren() {
return Collections.emptyList();
}
}
// These return the concrete, public types
public InnerNode getInnerNode() { return new InnerNode(); }
public LeafNode getLeafNode() { return new LeafNode(); }
// This returns the private interface type
public Node getRootNode() {
// Both concrete types can be returned here,
// because they both implement the interface
return getInnerNode(); // Works
//return getLeafNode(); // Works
}
// This uses only the interface type
public void traverseNode(Node node) {
System.out.println("Traversing "+node);
for (Node child : node.getChildren()) {
traverseNode(child);
}
}
}
In an external main
method, you can observe the limitations imposed by the private interface:
public static void main(String[] args) {
Tree tree = new Tree();
// The public concrete types can be used
Tree.LeafNode leafNode = tree.getLeafNode();
Tree.InnerNode innerNode = tree.getInnerNode();
// The private interface can not be used from outside:
//Tree.Node node = tree.getRootNode();
// This is possible: The class only uses its
// own private interface here
tree.traverseNode(tree.getRootNode());
}
In this example, you can call traverseNode
, passing in the Node
that is returned by getRootNode
, regardless of whether this node is a InnerNode
or a LeafNode
. In the current version, this will print something like
Traversing Tree$InnerNode
Traversing Tree$LeafNode
Traversing Tree$LeafNode
If you changed getRootNode
to return a LeafNode
, then it would only print
Traversing Tree$LeafNode
To put it simply, and as the name "private interface" already suggests: You can use this in order to hide the fact that two classes share a common ancestor.