Here I came across this phrase:
Implementing a private interface is a way to force the definition of the methods in that interface without adding any type information (that is, without allowing any upcasting).
I'm finding it difficult to understand this. Can some one explain this for me?
Here is an example of private interfaces.
public class Main {
private interface Animal {
void makeNoise();
}
public static final class Cow implements Animal {
@Override
public void makeNoise() {
System.out.println("Moo!");
}
}
public static final class Sheep implements Animal {
@Override
public void makeNoise() {
System.out.println("Bah!");
}
}
public static void main(String[] args) {
List<Animal> animals = Arrays.asList(new Cow(), new Sheep());
for (Animal animal : animals)
animal.makeNoise();
}
}
From within the class Main
you can refer to an Animal
and call makeNoise()
on it. Therefore you can have a List
of Animal
s of different types and use a for each loop to call makeNoise()
on them all.
However, outside the class Main
this is not possible. You can have a Cow
or a Sheep
and call makeNoise()
on either, but the interface Animal
and the interface method makeNoise()
are invisible.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With