6

静态方法的返回类型中的泛型似乎与继承相处得不好。请看下面的代码:

class ClassInfo<C>  {
  public ClassInfo(Class<C> clazz) {
    this(clazz,null);
  }  
  public ClassInfo(Class<C> clazz, ClassInfo<? super C> superClassInfo) {
  }
}

class A {
    public static ClassInfo<A> getClassInfo() {
        return new ClassInfo<A>(A.class);
    }
}

class B extends A {
    // Error: The return type is incompatible with A.getClassInfo()
    public static ClassInfo<B> getClassInfo() { 
        return new ClassInfo<B>(B.class, A.getClassInfo());
    }
}

我试图通过更改 A.getClassInfo() 的返回类型来规避这个问题,现在错误在另一个位置弹出:

class ClassInfo<C>  {
  public ClassInfo(Class<C> clazz) {
    this(clazz,null);
  }  
  public ClassInfo(Class<C> clazz, ClassInfo<? super C> superClassInfo) {
  }
}

class A {
    public static ClassInfo<? extends A> getClassInfo() {
        return new ClassInfo<A>(A.class);
    }
}

class B extends A {
    public static ClassInfo<? extends B> getClassInfo() { 
        // Error: The constructor ClassInfo<B>(Class<B>, ClassInfo<capture#1-of ? extends A>) is undefined
        return new ClassInfo<B>(B.class, A.getClassInfo());
    }
}

对静态方法进行严格检查的原因是什么?我该如何相处?更改方法名称似乎很尴尬。

4

2 回答 2

5

B 中的静态方法不会覆盖 A 中的静态方法,而是将其隐藏。JLS 8.4.8.3明确指出返回类型必须是可替换的,否则将无法编译:

如果具有返回类型 R1 的方法声明 d1 覆盖或隐藏具有返回类型 R2 的另一个方法 d2 的声明,则 d1 必须是 d2 的返回类型可替换(第 8.4.5 节),否则会发生编译时错误。

可替代性在 JLS #8.4.5 中定义:

当且仅当以下条件成立时,具有返回类型 R1 的方法声明 d1 可以返回类型替代具有返回类型 R2 的另一个方法 d2:

  • [...]
  • 如果 R1 是引用类型,则:
    • R1 是 R2 的子类型,或者 R1 可以通过未经检查的转换(第 5.1.9 节)转换为 R2 的子类型,或者
    • R1 = |R2|

在您的情况下: d1 是 B 中的方法, R1 是ClassInfo<B>, d2 是 A 和 R2 中的方法ClassInfo<A>。并且ClassInfo<B>不是ClassInfo<A>.

但是,ClassInfo<? extends B>可以转换为ClassInfo<? extends A>. 您可以在以下位置观察到这种行为:

void someMethod(){
    ClassInfo<B> b1 = (ClassInfo<B>) get1(); //does not compile
    ClassInfo<? extends B> b2 = (ClassInfo<? extends B>) get2(); //compiles
}

ClassInfo<A> get1() {
    return null;
}

ClassInfo<? extends A> get2() {
    return null;
}
于 2012-11-23T17:09:25.953 回答
4

您不能覆盖静态方法。因此,当您声明相同的静态方法时,您正在创建一个新方法。

public static ClassInfo<B> getClassInfo() { 
    return new ClassInfo<B>(B.class, A.getClassInfo());
}

但是,当您声明具有更改的返回类型的方法时,它不是有效的方法 hidden也不是 override。所以,getClassInfo()方法class AgetClassInfo()方法class B,相互冲突。因为A类的方法在B类中也是可见的。

因此,换句话说,class B具有相同的方法,因为它继承自class A,但返回类型发生了变化。并且由于方法的返回类型不被视为方法签名的一部分。因此冲突。

因此,您需要具有完全相同的返回类型。在这种情况下,B 类将忽略继承的方法,并使用它自己的方法。

于 2012-11-23T17:04:17.453 回答