Java泛型方法继承和覆盖规则

时间:2011-03-18 00:19:53

标签: java inheritance override abstract-class generic-method

我有一个抽象类,它有一个泛型方法,我想通过用特定类型替换泛型参数来覆盖泛型方法。所以在伪代码中我有以下内容:

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

6 个答案:

答案 0 :(得分:28)

我们这里有两种不同的方法,每种方法都有各自的类型参数。

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

这是一个名为T的类型参数的方法,由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方法实现了父类'方法。

答案 1 :(得分:10)

由于Java Generics中称为“Erasure”的概念,您看到了这个问题。 Java使用“擦除”来支持向后兼容性。即没有使用泛型的Java代码。

删除程序:
编译器将首先进行类型检查,然后尽可能地删除(擦除)所有类型参数,并在必要时插入TypeCasting。

示例:

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

答案 2 :(得分:1)

不,它无效。如果有GetAndParse引用的人使用扩展AnotherClass类来调用它,会发生什么?

答案 3 :(得分:1)

当有人引用类型GetAndParse并尝试调用getAndParse方法时,这变得毫无意义。如果Cat和Dog扩展了AnotherClass。我希望能够用Cat或Dog调用GetAndParse#getAndParse。但是实现已经尝试限制它并降低它的兼容性!

答案 4 :(得分:1)

你不能覆盖到特定类型T,因为事实上(如果你愿意,在字节码级别)只有一个方法getAndParse因为类型擦除(参见其他答案):< / p>

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

对于每种类型的T,都使用相同的方法。

你可以重载它(我认为):

public void getAndParse(SpecificClass... args); // (2)

但这不会与(1)蚂蚁的方法不同,它将通过通用代码调用

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

答案 5 :(得分:0)

静态方法无法覆盖

class Vehicle{
static void park(int location){
    System.out.println("Vehicle parking..");
}}

class Car extends  Vehicle{
@Override //error
void park(int location) { //error
    System.out.println("Car Parking..");
}}

私有方法无法覆盖

class Vehicle{
private void park(int location){
    System.out.println("Vehicle parking..");
}
void callPark(){
    park(100);
}}

class Car extends  Vehicle{
//@Override
void park(int location) {
    System.out.println("Car Parking..");
}}

class Demo {
public static void main(String[] args) {
    Vehicle v1=new Car();
   v1.callPark();
}}

最终方法无法覆盖

class Vehicle{
final void park(int location){
    System.out.println("Vehicle parking..");
}}

class Car extends  Vehicle{
//@Override
void park(int location) { //error
    System.out.println("Car Parking..");
}}