引用具有有界类型的对象

时间:2017-05-25 21:45:13

标签: java generics inheritance wildcard

我正在尝试编写节点网络,每个节点都包含对另一个节点的引用列表。 Node是一个抽象类,因此列表将引用node-children。

主要的抽象Node类 - 带有一个输入类型列表(它本身就是该类型的节点列表)。由于课程是抽象的,我只能实现其中一个孩子。

public abstract class Node {        
    ArrayList<Input<? extends Node>> inputs;

    public Node(){
        inputs = new ArrayList<Input<? extends Node>>();
    }

    public ArrayList<Input<? extends Node>> getInputNodes(){
        return(inputs);
    }

    public void killConnections() {
        for(Input<? extends Node> i:inputs){
            i.removefromInput(this);
        }
    }

    public abstract void something(); //not too important in this context....
}

我有不同类型的对象作为输入。 Node()的不同子节点可能具有不同类型的输入。因此,我创建了一个适用于泛型类型的输入类。输入类包含对继承自Node的其他对象的引用列表,如下所示:

public class Input<T extends Node> {
    ArrayList<T> inputs;

    public Input(){
        inputs = new ArrayList<T>();
    }

    public void removefromInput(T obj){
        inputs.remove(obj);
    }

    public void addToInput(T obj){
        inputs.add(obj);
    }

    public ArrayList<T> getInputs(){
        return inputs;
    }       
}

最后,我实际实现了节点类。这是Node的几个子节点之一,每个子节点可能有一组不同的Input类型,我在构造函数中定义。

public class ExplicitNode extends Node {  
    boolean active;

    public ExplicitNode(ExplicitNode inputNode){
        active = true;
        inputs.add(new Input<ExplicitNode>());
        inputs.get(0).addToInput(inputNode); //***Here i get an error
    }

    public void someMethod() {
        if(!inputs.get(0).getInputs().isEmpty()){           
            for(int i = 0; i< inputs.get(0).getInputs().size(); i++){
                //***Here i get an error too
                if(inputs.get(0).getInputs().get(i).active){ . 
                //do something....,
            }           
        }
    }
}

我收到以下错误:

  

类型中的addToInput方法(捕获#1-of?extends Node)   输入不适用于   arguments(ExplicitNode)

第二个错误(“活动”字段无法解析)也让我感到困惑 - 我实例化了<ExplicitNode>类型的输入,因此输入的arrayList也应该返回包含“ExplicitNode类型的对象”活跃的“领域??

我做错了什么?

2 个答案:

答案 0 :(得分:0)

在抽象节点中,您将输入声明为

ArrayList<Input<? extends Node>>

这意味着它不保证输入始终具有ExplicitNode类型。

您还需要将Node更改为通用,如下所示:

    public static abstract class Node< T extends Node<T> > {        
    ArrayList< Input<T> > inputs;

    public Node(){
        inputs = new ArrayList< Input<T> >();
    }

    public ArrayList< Input<T> > getInputNodes(){
        return inputs;
    }

    public void killConnections() {
        for(Input<T> i:inputs){
            i.removefromInput( getThis() );
        }
    }

    protected abstract T getThis();

    public abstract void something(); //not too important in this context....
}

public static class Input< T extends Node<T> > {
    ArrayList<T> inputs;

    public Input(){
        inputs = new ArrayList<T>();
    }

    public void removefromInput(T obj){
        inputs.remove(obj);
    }

    public void addToInput(T obj){
        inputs.add(obj);
    }

    public ArrayList<T> getInputs(){
        return inputs;
    }       
}

public static class ExplicitNode extends Node<ExplicitNode> {  
    boolean active;

    public ExplicitNode(ExplicitNode inputNode){
        active = true;
        inputs.add(new Input<ExplicitNode>());
        inputs.get(0).addToInput(inputNode); //***Here i get an error
    }

    protected ExplicitNode getThis(){
        return this;
    }

    public void someMethod() {
        if(!inputs.get(0).getInputs().isEmpty()){           
            for(int i = 0; i< inputs.get(0).getInputs().size(); i++){
                //***Here i get an error too
                if(inputs.get(0).getInputs().get(i).active){ 
                //do something....,
            }           
        }
    }
}

    @Override
    public void something() {
        // TODO Auto-generated method stub

    }
}

或者这是另一种不使用通用抽象类的方法。就个人而言,我仍然喜欢使用通用抽象类:

public static abstract class Node {        

    public abstract ArrayList< ? extends Input<? extends Node> > getInputNodes();

    public void killConnections() {
        for( Input<? extends Node> i : getInputNodes() ){
            i.removefromInput(this);
        }
    }

    public abstract void something(); //not too important in this context....
}

public static class Input<T extends Node> {
    ArrayList<T> inputs;

    public Input(){
        inputs = new ArrayList<T>();
    }

    public void removefromInput(Object obj){
        inputs.remove(obj);
    }

    public void addToInput(T obj){
        inputs.add(obj);
    }

    public ArrayList<T> getInputs(){
        return inputs;
    }       
}


public static class ExplicitNode extends Node {  
    ArrayList< Input<ExplicitNode> > inputs = new ArrayList<>();

    boolean active;

    public ExplicitNode(ExplicitNode inputNode){
        active = true;
        inputs.add( new Input<ExplicitNode>() );
        inputs.get(0).addToInput(inputNode); 
    }

    public ArrayList< ? extends Input<? extends Node> > getInputNodes(){
        return  inputs;
    }

    public void someMethod() {
        if ( !inputs.get(0).getInputs().isEmpty() ) {
            for (int i = 0; i < inputs.get(0).getInputs().size(); i++) {
                if (inputs.get(0).getInputs().get(i).active) {
                    // do something....,
                }
            }
        }
    }

    @Override
    public void something() {
        // TODO Auto-generated method stub          
    }
}

答案 1 :(得分:0)

所以我在这里添加了一个没有Generics的版本,但另一方面,一旦实际对象被实例化,依赖于Casting,我认为这比使用泛型要差得多:

public abstract class Node {        
    ArrayList<Input> inputs;

    public Node(){
        inputs = new ArrayList<Input>();
    }

    public ArrayList<Input> getInputNodes(){
        return(inputs);
    }

    public void killConnections() {
        for(Input i:inputs){
            i.removefromInput(this);
        }
    }

    public abstract void something(); //not too important in this context....
}

public class Input {
    ArrayList<Node> inputs;

    public Input(){
        inputs = new ArrayList<Node>();
    }

    public void removefromInput(Node obj){
        inputs.remove(obj);
    }

    public void addToInput(Node obj){
        inputs.add(obj);
    }

    public ArrayList<Node> getInputs(){
        return inputs;
    }       
}

public class ExplicitNode extends Node {  
    boolean active;

    public ExplicitNode(ExplicitNode inputNode){
        active = true;
        inputs.add(new Input());
        inputs.get(0).addToInput(inputNode);
    }

    //Note the ugly cast
    public void someMethod() {
        if(!inputs.get(0).getInputs().isEmpty()){  
            for(int i = 0; i< inputs.get(0).getInputs().size(); i++){
                Node node = inputs.get(0).getInputs().get(i);
                if(node instanceof ExplicitNode){
                    ExplicitNode explicitNode = (ExplicitNode)node;
                    if(explicitNode.active){
                        //do something
                    }
                }
            }      
        }
    }
}

我仍然预感到更智能的继承设置实际上可以在不依赖于泛型的情况下工作,但是我无法理解它...