简体   繁体   中英

Implementing a generic interface with a raw type

I have a generic tree, the generic parameter is the data type stored by the nodes:

class TreeNode<D>{  
    public D data;  
    .....
}

Then a visitor interface to use along with a tree transversal:

interface Visitor<D> {
    void visit(TreeNode<D> node);
}

Some visitors can take advantage of generics:

class DataListCreator<D> implements Visitor<D> {
    List<D> dataList = new ArrayList<D>();
    public void visit(TreeNode<D> node) {
         dataList.add(node.data);
    }
    public List<D> getDataList() {
        return dataList;
    }

But others don't, they would fit better in a raw class

class NodeCounter implements Visitor {
    private int nodeCount = 0;
    public void visit(TreeNode node) {
        nodeCount++;
    }
    public int count() {
        return nodeCount;
    }

But I don't know how implement this last case, the code above don't compile as I have to implement the generic interface not the raw one. I tried implementing

Visitor<?> 

with the same result. So my question is, I'm forced to use a generic type

NodeCounter<D> 

to implement the Visitor interface?.

Thanks.

the code above don't compile

I tried compiling your example, and it works fine. I'm using Java 6. What was the compilation error you got?

This is what I successfully compiled:

class TreeNode<D>{  
    public D data;  
}

interface Visitor<D> {
    void visit(TreeNode<D> node);
}

class NodeCounter implements Visitor {
    private int nodeCount = 0;
    public void visit(TreeNode node) {
        nodeCount++;
    }
    public int count() {
        return nodeCount;
    }
}

Java generics are very powerful, and raw types should almost never be necessary.

You probably want to put some wildcards in. For instance, a visitor may need not know the exact generic argument of the TreeNode s it is visiting:

interface TreeNodeVisitor<D> {
    void visit(TreeNode<? extends D> node);
}

Perhaps better(?), a TreeNode may not need to know the exact type of visitor.

interface TreeNode<D> {
    void accept(TreeNodeVisitor<? super D> visitor);
}

In short - yes, you do need to give the generic interface a type argument.

What you probably should do, is implemenet a non-generic (and possibly empty) interface ITreeNode , that ITreeNode<D> inherits from. Any methods that don't need to be generic are declared in this intercace instead. Then, do the same thing for IVisitor , and NodeCounter can inherit the non-generic Visitor interface.

Short schematic:

ITreeNode
ITreeNode<D> implements TreeNode

IVisitor
IVisitor<D> implements IVisitor

NodeCounter implements IVisitor

(Note: I used the C# convention to prefix interfaces with I. NodeCounter is meant to be a class, while the others are interfaces...)

Java Generics are explicitly designed to be interoperable with raw types using a technique known as Erasure .

So the situation you are describing is directly supported and should compile fine:

class TreeNode<D>{
    public D data;  
}

interface Visitor<D> {
    void visit(TreeNode<D> node);
}

class NodeCounter implements Visitor {
    private int nodeCount = 0;
    public void visit(TreeNode node) {
        nodeCount++;
    }
    public int count() {
        return nodeCount;
    }
}

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