如何调用泛型类型对象的方法?

时间:2011-02-26 20:54:51

标签: java generics

以下代码给出了错误:

SceneNode.java:17: cannot find symbol
symbol  : method execute() location:
class java.lang.Object
                operation.execute();
                         ^ 1 error

代码:

import java.util.LinkedList;
import java.util.Iterator;

public class SceneNode<T>{
    T operation;    
    public SceneNode() {
    }   
    public SceneNode(T operation) {
        this.operation = operation;
    }
    public void setOperation(T operation) {
        this.operation = operation;
    }
    public void doOperation() {
        operation.execute();
    }
}

这是一个简单的场景图的缩减(为了您的可读性)。节点可以是模型,转换,开关等,因此我创建了一个名为operation的变量,其类型由T类变量定义。这样我就可以传递Transformation / Model / Switch对象(具有execute方法)并将其传递给它:

SceneNode<Transformation> = new SceneNode<Transformation>(myTransformation);

我非常确定拥有SceneNode的基类并且为所有不同类型的节点进行子类化将是一个更好的主意(我正在尝试泛型,最近才了解它们)。为什么这不起作用?我必须遗漏一些关于泛型的基本信息。

4 个答案:

答案 0 :(得分:9)

它不起作用,因为T可能是任何类型,而Java是静态类型的。编译器不知道您是否会尝试创建SceneNode<String> - 那么execute会做什么?

一种选择是创建适当的界面,例如

public interface Executable {
    void execute();
}

然后约束T中的SceneNode来实施Executable

public class SceneNode<T extends Executable> {
    ...
}

(我发现T必须扩展 Executable而不是中实现它在源代码中有点奇怪,但随后T最终可能成为一个界面,所以我觉得这很有意义。)

然后它应该工作正常。当然你可以使Executable成为一个抽象的超类 - 或者甚至是一个(非最终的)具体类 - 如果你愿意,但我通常更喜欢使用一个接口,除非我有一些理由不去。

答案 1 :(得分:8)

我猜你是来自C ++背景。

编译器不知道T可能是什么类型的东西,因为你没有告诉它。

如果你有一个名为Executable的接口,它定义了你的execute()方法,那么你需要这样做:

public class SceneNode<T extends Executable> {
    // ... 
}

现在,编译器将知道T是Executable,并且可以访问该接口上的所有方法。

答案 2 :(得分:1)

Java是静态类型语言。您必须在编译时知道类型才能调用方法。您可以使用定义Executable方法的接口execute()代替子类。 T(没有任何<T extends SomeClass>)只有java.lang.Object定义的方法。

答案 3 :(得分:0)

最近,我遇到了不得不在通用对象上调用方法的情况。行动起来对我来说很有效。

public class SceneNode<T>{
    T operation;    
    public SceneNode() {
    }   
    public SceneNode(T operation) {
        this.operation = operation;
    }
    public void setOperation(T operation) {
        this.operation = operation;
    }
    public void doOperation() {
        Method m = operation.getClass().getMethod("execute");
        m.invoke(operation);
    }
}