2011-03-18 136 views
22

我有一个抽象类,它有一个泛型的方法,我想通过将泛型参数替换为特定类型来覆盖泛型方法。所以在伪代码我有以下几点:Java的泛型方法的继承和覆盖规则

public abstract class GetAndParse { 
    public SomeClass var; 

    public abstract <T extends AnotherClass> void getAndParse(T... args); 
} 

public class Implementor extends GetAndParse { 
    // some field declarations 

    // some method declarations 

    @Override 
    public <SpecificClass> void getAndParse(SpecificClass... args) { 
    // method body making use of args 
    } 
} 

但由于某种原因,我不能这样做?我是否犯了某种语法错误,或者这种继承和覆盖是不允许的?具体来说,我得到一个关于@Override的错误,因为eclipse IDE不停地提醒我执行getAndParse

下面是我希望上面的代码工作。在我的代码中的其他地方,有一种方法需要实现GetAndParse的对象实例,这意味着它们具有我可以使用的getAndParse方法。当我打电话getAndParse该实例上编译器检查,看看我是否在正确的方式使用的T具体实例,所以特别T应该扩展AnotherClass,它应该是SpecificClass

+0

伪代码太抽象,需要更多信息 – irreputable 2011-03-18 00:48:48

+0

使用'public abstract void getAndParse(Args ... args);'没有任何意义。什么是类型参数适合?编译器应该如何确定它的实际值以及它在哪里使用它? – maaartinus 2011-03-18 00:50:19

+0

你能给我们一个完整的例子,它实际上是可编译的(除了有问题的错误),并产生你提到的错误? – 2011-03-18 01:47:24

回答

23

我们有这里什么是两种不同的方法,每个单独的类型参数。

public abstract <T extends AnotherClass> void getAndParse(Args... args); 

这是与名为T A型参数的方法,以及通过AnotherClass界,意思的AnotherClass各亚型被允许作为类型参数。

public <SpecificClass> void getAndParse(Args... args) 

这是与名为SpecificClass类型参数,通过Object界(这意味着每个类型被允许作为类型参数)的方法。你真的想要这个吗?

是否在Args内部使用了类型参数?我认为问题会在那里。


编辑:

public abstract <T extends AnotherClass> void getAndParse(T... args); 

的意思是,该方法的呼叫者可他想调用的方法哪种类型的参数决定的,只要这是某些子类型为AnotherClass。这意味着实际上可以用AnotherClass类型的任何对象调用该方法。

由于调用者可以决定类型参数,因此不能在子类中将参数类型限制为SpecificClass - 这不是该方法的实现,而是另一个具有相同名称(重载)的方法。

也许你想是这样的:

public abstract class GetAndParse<T extends AnotherClass> { 
    public SomeClass var; 

    public abstract void getAndParse(T... args); 
} 

public class Implementor extends GetAndParse<SpecificClass> { 
    // some field declarations 

    // some method declarations 

    @Override 
    public void getAndParse(SpecificClass... args) { 
    // method body making use of args 
    } 
} 

现在getAndParse方法实现父类的方法。

+3

我不想要一个类型参数。我希望编译器检查并确保'SpecificClass'是'AnotherClass'的扩展。 – davidk01 2011-03-18 03:41:38

1

不,它是无效的。如果某个参与GetAndParse的人将其称为的其他类延伸AnotherClass,会发生什么情况?

+0

我不明白为什么这是一个问题。我有一个扩展'GetAndParse'并将'T'的类型修正为'SpecficClass',编译器检查以确保当我有一个'Implementor'实例并调用'getAndParse'时,在我的代码中扩展'AnotherClass'。与不匹配'SpecificClass'的类型,我应该得到一个错误。 – davidk01 2011-03-18 01:43:58

+0

@ davidk01:由GetAndParse提供的合同表示每个实现它的人都必须为任何扩展AnotherClass的类型这样做。给定'GetAndParse foo = new Implementor();'你必须能够调用'foo.getAndParse'作为AnotherClass的任何扩展 - 如果编译器没有强制执行这个,你可以使用Object,泛型的意义在于确保编译时安全类型 – Erik 2011-03-18 08:28:34

1

当某人有一个引用类型GetAndParse并尝试调用getAndParse方法时,这变成了无稽之谈。如果猫和狗延长AnotherClass。我希望能够用Cat或Dog来调用GetAndParse#getAndParse。但是实现已经试图限制它,并使其不兼容!

+0

这就是你想要做的事情是不可能的原因,如果我以一种你不喜欢的方式来构建它,我表示歉意。编译时间泛型不能为您执行。编译器如何知道运行时会出现哪些子类?实现者完全有可能通过工厂界面返回,并且来自不同的库,您甚至不会编译它们!在编译时无法检查类型参数的缩小情况以确保安全。 – Affe 2011-03-18 04:17:08

8

由于Java泛型中的“擦除”这个概念,你会看到这个问题。 Java使用“擦除”来支持向后兼容性。即不使用泛型的Java代码。

擦除过程:
编译器将首先做一个类型检查,然后它会删除(清除)所有类型参数尽可能,还插入铸字在以往任何时候必要的。

例如:

public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass); 

将变得

public abstract void getAndParse(AnotherClass paramAnotherClass); 

在类 “Implementor.java”,

代码

public <SpecificClass> void getAndParse(T paramAnotherClass) 

将变得

public void getAndParse(SpecificClass paramAnotherClass){ } 

编译器会看到你没有正确实现抽象方法。 抽象方法和实现的方法之间存在类型不匹配。这就是你看到错误的原因。

更多细节可以在这里找到。 http://today.java.net/pub/a/today/2003/12/02/explorations.html

1

你不能覆盖特定类型T,因为在实际上(在字节码级,如果你愿意的话),因为类型擦除(见其他答案)的只有一个方法getAndParse:

public abstract void getAndParse(AnotherClass... args); // (1) 

每T的类型,使用相同的方法。

可以超载它(我认为):

但这不会从一个不同的方法(1)蚂蚁会被通用代码调用:

T x = whatever; 
    object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass