2017-05-25 2 views
0

Ich versuche ein Netzwerk von Knoten zu programmieren, wobei jeder Knoten eine Liste von Referenzen auf einen anderen Knoten enthält. Node ist eine abstrakte Klasse, daher verweisen die Listen auf Node-Children.Referenzieren von Objekten mit begrenzten Typen

Die abstrakte Knoten-Hauptklasse - enthält eine Liste von Eingabetypen (die selbst eine Liste von Knoten dieses Typs ist). Da die Klasse abstrakt ist, kann ich nur eines ihrer Kinder instanziieren.

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

Ich habe verschiedene Arten von Objekten, die als Eingabe fungieren. Verschiedene untergeordnete Knoten() können verschiedene Arten von Eingaben haben. Ich erstelle daher eine Eingabeklasse, die auf einem generischen Typ funktioniert. Die Eingangsklasse, eine Liste von Referenzen auf andere Objekte enthält, von Knoten zu erben, sieht wie folgt aus:

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; 
    }  
} 

Schließlich meine eigentliche Knotenklasse implementiert. Dies ist einer von mehreren Kindknoten, jedes Kind hat möglicherweise einen anderen Satz von Eingabetypen, die ich im Konstruktor definiere.

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

ich folgende Fehlermeldung erhalten:

The method addToInput(capture#1-of ? extends Node) in the type Input is not applicable for the
arguments (ExplicitNode)

Der zweite Fehler auch (Das Feld „aktiv“ nicht aufgelöst werden kann) mich verwirrt - ich instanziiert einen Eingang vom Typ <ExplicitNode>, damit die Arraylist des Eingangs sollte auch Objekte des Typs ExplicitNode zurückgeben, die das "aktive" Feld ??

Was mache ich falsch?

+0

'die Eingabe des Arraylist auch sollte um nicht bekommen ... Objekte des Typs ExplicitNode' - nein, weil yo Sie parametrisieren die 'ArrayList' nicht als solche. –

+0

Ich dachte, dass, wenn ich "Input " im Klassenheader hat, das T innerhalb "ArrayList Eingaben" im Körper bereits als erben von Node verstanden wird. Wenn also die Eingabe erstellt wird, enthält die ArrayList daher Objekte vom Typ ExplicitNode. – user3641187

Antwort

0

Im abstrakten Knoten Sie Eingänge als

ArrayList<Input<? extends Node>> 

die erklärt haben, bedeutet, dass es gurantee nicht, dass Eingaben immer ExplicitNode Typ.

Sie benötigen Knoten zu ändern, generisch zu sein als auch, wie folgt aus:

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 

    } 
} 

Oder hier ein anderer Ansatz ist generisch abstrakte Klasse ohne Verwendung. Persönlich bevorzuge ich immer noch generische abstrakte Klasse zu verwenden:

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   
    } 
} 
+0

Das war schnell, danke für den Kommentar ..! Funktioniert fast - außer killConnections(), die Sie in Ihrer Antwort weggelassen haben, funktioniert nicht für Eingabe . – user3641187

+0

Auch wenn ich davon ausgehe, dass Generika es erlauben werden, mein Problem zu umgehen - ich frage mich, ob dies nicht durch die Entwicklung eines intelligenteren Vererbungsschemas gelöst werden kann? Das Hinzufügen all dieser Subtypen scheint nicht zu sauber zu sein. – user3641187

+0

Ich habe den Code mit killConnections aktualisiert. Sie können versuchen, anstelle von Generika Umwandlungen zu verwenden oder das Eingabefeld in der abstrakten Klasse nicht zu verwenden. Ich denke über einen anderen Ansatz nach, wenn ich einen finde. – tsolakp

0

Also habe ich hier eine Version ohne Generics hinzugefügt, aber auf der anderen Seite unter Berufung auf Casting einmal eigentliche Objekte ist instanziert, was ich denke, ist deutlich schlechter als die Verwendung von Generika:

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

ich habe immer noch das Gefühl, dass ein intelligenter Vererbungs Setup tatsächlich, ohne sich auf die Generika funktionieren könnte, aber mein Geist zurückkehren

Verwandte Themen