开发者

a more extensive recursion/generics question

开发者 https://www.devze.com 2023-03-20 12:36 出处:网络
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, 开发者_StackOverflow中文版however, restate th

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, 开发者_StackOverflow中文版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


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


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>.

0

精彩评论

暂无评论...
验证码 换一张
取 消