Reputation: 387
Based on the question asked and answered here, I have a second, more complex one (at least in my opinion). To make reading (and answering) easier, I will, however, restate the complete code example here:
Let us begin by defining a set of classes/interfaces:
public interface Node<NT extends Node<NT, ET>, ET extends Edge<NT, ET>> {
/* internal datastructures here */
}
public interface Edge<NT extends Node<NT, ET>, ET extends Edge<NT, ET>> {
/* internal datastructures here */
}
public interface Graph<NT extends Node<NT, ET>, ET extends Edge<NT, ET>> {
/* internal datastructures here */
}
public class JunctionNode implements Node<JunctionNode, RoadEdge> {
}
public class RoadEdge implements Edge<JunctionNode, RoadEdge> {
}
public class StreetGraph implements Graph<JunctionNode, RoadEdge> {
}
public class PTNode implements Node<PTNode, PTEdge> {
}
public class PTEdge implements Edge<PTNode, PTEdge> {
}
public class PTGraph implements Graph<PTNode, PTEdge> {
}
I now need to define an intermodal graph, i.e. a graph containing PTEdges as well as RoadEdges. In my opinion, I would do this by stating
public class IntermodalGraph implements Graph<Node, Edge> {
}
Here the compiler complaints on Node and Edge, since Node is defined to have two type parameters whereupon one is derived from the second type (here Edge). This means, I would have to state
public class IntermodalGraph implements Graph<Node<Node, Edge>, Edge> {
}
So far, the first type parameter (Node) is ok, but the second one (Edge) fails since edges takes two type parameters again, the first one derived from Node. So, I would write
public class IntermodalGraph implements Graph<Node<Node, Edge>, Edge<Node<Node, Edge>>, Edge> {
}
Now, the second type parameter is ok, but the first one is (obviously) "bad" again.
In the end, I would like to achieve some code like
IntermodalGraph ig = new IntermodalGraph();
ig.add(new PTEdge());
ig.add(new RoadEdge());
Set<Edge> edges = ig.getEdges();
So does anybody have an idea how to achieve this while keeping type safe?
lg, Matthias
Upvotes: 3
Views: 185
Reputation: 6181
As already pointed out by toto, you define a type checkable contract and then proceed to break it -- and the compiler intervenes. A type safe solution is to simply split the contract in two, a weaker and a stricter one: A Graph<N extends Node<?, ?>, E extends Edge<?, ?>>
interface as well as a StrictGraph<N extends Node<N, E>, E extends Edge<N, E>>
interface which extends Graph<N, E>
.
Upvotes: 0
Reputation: 53531
Since your classes already specify the generics, you could declare your IntermodalGraph
class as
public class IntermodalGraph<NT extends Node<NT, ET>, ET extends Edge<NT, ET>> implements Graph<NT, ET> {
}
And this should not throw any warnings.
** EDIT **
You can't accomplish what you want, that is having
IntermodalGraph ig = new IntermodalGraph();
ig.add(new PTEdge());
ig.add(new RoadEdge());
Set<Edge> edges = ig.getEdges();
not throw any unchecked
warnings, unless you add @SuppressWarnings("unchecked")
annotations. But, it is still valid Java syntax and will work; the generic NT
will default to Node
and ET
to Edge
Upvotes: 2