我有这堂课:
public abstract class Addressable {
abstract <T extends "this" Addressable> void hardEquals(T t);
}
方法hardEquals(T t)不是我想要的。我想要的是将T绑定为this
的同一类。换句话说,当我使用具体类Addressable
扩展类MyAddressable
时,我希望方法hardEquals()
具有签名:
void hardEquals(MyAddressable t);
为了完整性:
public class MyAddressable extends Addressable {
void hardEquals(MyAddressable t);
}
答案 0 :(得分:2)
一般来说,这是不可能的。在考虑一下你的场景时,问题就变得清晰了。您拥有该类Addressable
及其方法hardEquals
,它要求其参数的类型等于此。然后你有子类
public class MyAddressable extends Addressable {
void hardEquals(MyAddressable t);
}
似乎按预期工作。现在想象一下子类的子类:
public class GrandChild extends MyAddressable {
void hardEquals(MyAddressable t);
}
在这里,您有一个必须接受MyAddressable
作为hardEquals
'参数的类,因为不允许通过缩小参数类型来覆盖方法,即不接受超类接受的东西。毕竟,您总是可以使用MyAddressable
类型的变量来实际引用GrandChild
的实例。将参数限制为hardEquals
以匹配对象的实际运行时类型是不可能的。
所以期望的“参数类型必须匹配this
类型”规则与“子类方法必须接受超类所做的所有参数”规则冲突。
请注意,这通常与类型系统的实际限制相混淆,同样的事情对返回类型不起作用。由于允许为子类缩小返回类型,因此在某些情况下保证返回this
类型的愿望可能是合理的,例如:
class Base {
Base/*actually this type*/ clone() { … }
}
class SubClass extends Base {
SubClass/*actually this type*/ clone() { … }
}
class GrandChild extends SubClass {
GrandChild/*actually this type*/ clone() { … }
}
有效,但没有正式的方法来指定保证this
类型被返回,因此由程序员的规则来为每个子类添加正确的覆盖。
但是,如上所述,对于参数类型,这通常不起作用,因为您无法缩小子类中参数的类型。
答案 1 :(得分:1)
你可以从Comparable
借用一个技巧,并在类声明本身中指定泛型类型:
public abstract class Addressable<T> {
abstract <T> void hardEquals(T t);
}
这会产生稍微笨重的类定义,但它应该满足您的要求
public class HomeAddress extends Addressable<HomeAddress> {
void hardEquals(HomeAddress t) {
// implementation
}
}
答案 2 :(得分:1)
我不知道问题的清洁解决方案。
你可以考虑这样的事情:
public abstract class Addressable<T extends Addressable<T>> {
abstract void hardEquals(T other);
}
public class MyAddressable extends Addressable<MyAddressable> {
@Override
void hardEquals(MyAddressable other) {
// ...
}
}
但在某些情况下这可能会失败,例如:
public class FakeAddressable extends Addressable<MyAddressable> {
@Override
void hardEquals(MyAddressable aT) {
// ...
}
}
答案 3 :(得分:1)
如果您正在寻找能够仅才能与完全相同类型的对象一起使用的hardEquals
,那么此类内容应该有效:
public abstract class Addressable<T extends Addressable<T>> {
abstract boolean hardEquals(T t);
}
class X extends Addressable<X> {
@Override
boolean hardEquals(X t) {
return true;
}
}
class Y extends Addressable<Y> {
@Override
boolean hardEquals(Y t) {
return true;
}
}
public void test() {
X x = new X();
if ( x.hardEquals(x)) {
System.out.println("Ok");
}
Y y = new Y();
// Fails!
if ( x.hardEquals(y)) {
System.out.println("Not OK");
}
}
正如@Holger正确地指出的那样 - 在扩展子类时这没有用。