Question

I have an interface Node that asks for the method:

public HashSet getNeighbour();

NodeVariable implements Node, and its neighbours are of type NodeFunction (that implements Node, too), and I wrote the method:

public HashSet<NodeFunction> getNeighbour();

(and viceversa in NodeFunction class).

I found out that if I change the signature of method in Node to:

public HashSet<Node> getNeighbour();

then on the methods in NodeVariable and NodeFunction I get the error:

Error getNeighbour() in factorgraph.NodeFunction cannot implement getNeighbour() in factorgraph.Node return type java.util.HashSet is not compatible with java.util.HashSet NodeFunction.java

This is not really clear.

I found:

Overriding return type in extended interface - Bad idea?

and

Java - Overriding return type of extended interface when return type uses generics for own method parameter types

and now I changed the Node method signature in:

public HashSet<? extends Node> getNeighbour();

thus the compiler stops complaining.

Is it right? Why HashSet is not considered like an "extension" of HashSet?

Was it helpful?

Solution

HashSet<Node> and HashSet<NodeFunction> aren't compatible, even though NodeFunction implements/subclasses Node. Similarly, neither are List<Number> and List<Integer>. Integer subclasses Number.

static List<Number> getNumberList(int size) {
    //ArrayList<Integer> numList = null; //Doesn't compile
    ArrayList<Number> numList = null; //Compiles
    return numList;
}

If the compiler allowed what your trying to do, then I could do the following and a ClassCastException would be thrown, which is the exact reason generics was created.

import java.util.HashSet;
import java.util.Set;

public class Main {

    public static void main( String[] args ) {
        Node nd = getInstance();
        Set<Node> ndSet = nd.getNeighbour();
        ndSet.add( new NodeSign() );
        nd.removeSingleNeighbor(); //throws ClassCastException
    }

    static Node getInstance() {
        return new NodeVariable();
    }
}

interface Node {
    public Set<Node> getNeighbour();
    public void removeSingleNeighbor();
}

class NodeVariable implements Node {
    Set<NodeFunction> ndFuncList = new HashSet<NodeFunction>();
    public Set<NodeFunction> getNeighbour(){ return ndFuncList; } //wont' compile

    //HERE!!!!

    public void removeSingleNeighbor() { 
        NodeFunction ndFunc = (NodeFunction)ndFuncList.toArray()[ndFuncList.size()-1]; //throws ClassCastException
    }
}

class NodeFunction implements Node {
    public Set<NodeFunction> getNeighbour(){ return null; } //won't compile
    public void removeSingleNeighbor() {}
}

class NodeSign implements Node {
    public Set<NodeFunction> getNeighbour(){ return null; } //won't compile
    public void removeSingleNeighbor() {}
}

Everything is semantically/syntactically valid except public Set<NodeFunction> getNeighbour(){}. The Java tutorials cover this issue.

OTHER TIPS

First, it's a better idea to define the methods in your interfaces in terms of other interfaces and not concrete implementations. What I want to say is that the getNeighbour() method should be:

public Set getNeighbour();

And since we know that it can only return Nodes (or subtypes of Node), we might as well define it like this:

public Set<? extends Node> getNeighbour();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top