开发者

Implementing a generic interface with a raw type

开发者 https://www.devze.com 2022-12-18 20:20 出处:网络
I have a generic tree, the generic parameter is the data type stored by the nodes: class TreeNode<D>{

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 que开发者_Go百科stion 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 TreeNodes 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;
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号