简体   繁体   中英

Is there a way of specifying a nested generic without specifying a type twice in Java 8+

Given the following example...

S denotes a start Node of ConcreteType A

T denotes a end Node of ConcreteType B

E denotes an Edge with S as start Node and T as end Node

EdgeSet has a set of Edges accessed by an interface methods

SomeObject o returns an EdgeSet interface via a method SomeObject.getEdges();

A class definition defined using generics as follows...

    public class EdgeSet<S extends Node, T extends Node, E extends Edge<S, T>> { ... }

    public class SomeObject {

      protected EdgeSet<ConcreteNodeA, ConcreteNodeB, ConcreteEdge<ConcreteNodeA, ConcreteNodeB>> someEdgeSet;

      ...

      public EdgeSet<? extends ConcreteNodeA, ? extends ConcreteNodeB, ? extends ConcreteEdge<? extends ConcreteNodeA, ? extends ConcreteNodeB>> getEdges() { 
        //returns someEdgeSet... 
      }
    }

Usage Example...

    EdgeSet<? extends ConcreteNodeA, ? extends ConcreteNodeB, ? extends ConcreteEdge<? extends ConcreteNodeA, ? extends ConcreteNodeB>> exampleEdgeSet = o.getEdges();

Is there some way of defining this code, and the code which uses the member method without defining things twice?

For example:

public class EdgeSet<E extends Edge<S extends Node, T extends Node>> { ... }

EdgeSet<ConcreteEdge<? extends ConcreteNodeA, ? extends ConcreteNodeB>>

protected EdgeSet<ConcreteEdge<ConcreteNodeA, ConcreteNodeB>>

If not, is there somewhere where you can put through an RFC to reduce redundant information?

Is there some way of defining this code, and the code which uses the member method without defining things twice?

Given your EdgeSet as you currently define it, the only alternative I see is to use an Edge implementation that is non-generic:

public class ConcreteEdgeAB extends Edge<ConcreteNodeA, ConcreteNodeB> {
    // ...
}

Then you could write declarations such as

protected EdgeSet<ConcreteNodeA, ConcreteNodeB, ConcreteEdgeAB> someEdgeSet;

That still has some redundancy, however, because ConcreteNodeA and ConcreteNodeB are the only types you can use for S and T when you use ConcreteEdgeAB as E . Moreover, it's not as flexible is you would probably like.


I'm inclined to think that the main problem is that you have over-parameterized. If your Edge type is itself parameterized by the node types of its ends, then it is inherently redundant to parameterize a set of edges on the node types as well -- an edge set should need only to be parameterized on the type of edges it contains:

interface Edge<S extends Node, T extends Node> {
}

// The bounds on the type parameters of Edge effectively apply here, too:
public class EdgeSet <E extends Edge<?, ?>> {
    // ...
}

public class SomeObject {

    protected EdgeSet<ConcreteEdge<ConcreteNodeA, ConcreteNodeB>> someEdgeSet;

    ...

    public EdgeSet<? extends ConcreteEdge<? extends ConcreteNodeA, ? extends ConcreteNodeB>> getEdges() { 
        return someEdgeSet;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM