有界类型参数:覆盖时无法访问子类型方法
Bounded type parameters: cannot access subtype methods when overriding
我刚开始在 Java 中使用有界类型,我不确定以下是因为继承使用不当导致的编程错误还是 javac
错误
我需要定义两种不同类型的对象:必须管理的事物和那些事物的管理者。这就是为什么我创建了一个抽象 class 来模拟那些东西的共同行为
public abstract class AbstractThing {
// Common method implemented
public void hello() {
System.out.println("HI, I'm AbstractThing");
}
}
以及用于定义这些事物的管理器必须实现的方法的接口
public interface AbstractManager {
// Operation that a things' manager must implement
public <T extends AbstractThing> void greet(T t);
}
所以假设我创建了两个具体的东西 classes,其中一个只是继承了抽象的东西:
public class Thing extends AbstractThing {
// Constructor
public Thing() {}
}
但另一个实现了自己的方法:
public class AnotherThing extends AbstractThing {
// Constructor
public AnotherThing() {}
// Extra method which this class implements
public void goodbye() {
System.out.println("BYE, I'm AnotherThing");
}
}
但是当我这样定义一个manager时:
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the interface's method fails
@Override
public <AnotherThing extends AbstractThing>
void greet(AnotherThing t) {
// I can use this method, which AnotherThing inherits from AbstractThing
t.hello();
// But I can't use this one defined by AnotherThing
t.goodbye();
}
}
我收到错误:
AnotherManager.java:15: error: cannot find symbol
t.goodbye();
^
symbol: method goodbye()
location: variable t of type AnotherThing
where AnotherThing is a type-variable:
AnotherThing extends AbstractThing declared in method <AnotherThing>greet(AnotherThing)
1 error
我不明白为什么,因为它将 class 识别为 AnotherThing
,但将其处理为 AbstractThing
。我试图将对象转换为子class,但它不起作用
我还检查过只有当我尝试访问子类型方法时才会发生这种情况,因为以下管理器编译并完美运行:
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the method defined into the interface
@Override
public <Thing extends AbstractThing>
void greet(Thing t) {
t.hello();
}
// I can overload the method "greet" without overriding the interface
// and it works for AnotherThing
public void greet(AnotherThing t) {
t.hello();
t.goodbye();
}
}
知道那里发生了什么吗?
原因如下
如果你这样做不难理解
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the interface's method fails
@Override
public <T extends AbstractThing>
void greet(T t) {
// I can use this method, which T inherits from AbstractThing
t.hello();
// But I can't use this one because T inherits from AbstractThing which does not know this method
t.goodbye();
}
}
换句话说,“extends”前面的词不应该是class名称,而是通用标识符(变量名)。
在这种情况下,由于 T(或无论您如何称呼它)是 AbstractThing,它不知道 goodbye() 是什么。
现在,为什么你的最后一个例子有效?
因为你说 greet 接收的是 AnotherThing 类型的对象,而不是像 T 这样的泛型类型。
AnotherThing
中的<AnotherThing extends AbstractThing>
与classAnotherThing
无关。它是类型参数的名称,就好像它被称为 T
一样。它表现得像 AbstractThing
的原因是因为我们只知道它是这样的。您的方法不知道它是如何参数化的;它所知道的是它得到了 AbstractThing
的子 class。这对于我们需要捕获类型的构造很有用,但我们不关心它是什么子类型,例如:
<T extends AbstractThing> void copy(List<T> from, List<T> to) {
for (T t : from) {
t.hello();
to.add(t);
}
}
但是如果你想要AbstractManager
的专门子class来管理AnotherThing
,类型参数应该在class,而不是方法:
public interface AbstractManager<T extends AbstractThing> {
// Operation that a things' manager must implement
public void greet(T t);
}
public class AnotherManager implements AbstractManager<AnotherThing> {
@Override
public void greet(AnotherThing t) {
t.hello();
t.goodbye();
}
}
我刚开始在 Java 中使用有界类型,我不确定以下是因为继承使用不当导致的编程错误还是 javac
错误
我需要定义两种不同类型的对象:必须管理的事物和那些事物的管理者。这就是为什么我创建了一个抽象 class 来模拟那些东西的共同行为
public abstract class AbstractThing {
// Common method implemented
public void hello() {
System.out.println("HI, I'm AbstractThing");
}
}
以及用于定义这些事物的管理器必须实现的方法的接口
public interface AbstractManager {
// Operation that a things' manager must implement
public <T extends AbstractThing> void greet(T t);
}
所以假设我创建了两个具体的东西 classes,其中一个只是继承了抽象的东西:
public class Thing extends AbstractThing {
// Constructor
public Thing() {}
}
但另一个实现了自己的方法:
public class AnotherThing extends AbstractThing {
// Constructor
public AnotherThing() {}
// Extra method which this class implements
public void goodbye() {
System.out.println("BYE, I'm AnotherThing");
}
}
但是当我这样定义一个manager时:
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the interface's method fails
@Override
public <AnotherThing extends AbstractThing>
void greet(AnotherThing t) {
// I can use this method, which AnotherThing inherits from AbstractThing
t.hello();
// But I can't use this one defined by AnotherThing
t.goodbye();
}
}
我收到错误:
AnotherManager.java:15: error: cannot find symbol
t.goodbye();
^
symbol: method goodbye()
location: variable t of type AnotherThing
where AnotherThing is a type-variable:
AnotherThing extends AbstractThing declared in method <AnotherThing>greet(AnotherThing)
1 error
我不明白为什么,因为它将 class 识别为 AnotherThing
,但将其处理为 AbstractThing
。我试图将对象转换为子class,但它不起作用
我还检查过只有当我尝试访问子类型方法时才会发生这种情况,因为以下管理器编译并完美运行:
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the method defined into the interface
@Override
public <Thing extends AbstractThing>
void greet(Thing t) {
t.hello();
}
// I can overload the method "greet" without overriding the interface
// and it works for AnotherThing
public void greet(AnotherThing t) {
t.hello();
t.goodbye();
}
}
知道那里发生了什么吗?
原因如下
如果你这样做不难理解
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the interface's method fails
@Override
public <T extends AbstractThing>
void greet(T t) {
// I can use this method, which T inherits from AbstractThing
t.hello();
// But I can't use this one because T inherits from AbstractThing which does not know this method
t.goodbye();
}
}
换句话说,“extends”前面的词不应该是class名称,而是通用标识符(变量名)。
在这种情况下,由于 T(或无论您如何称呼它)是 AbstractThing,它不知道 goodbye() 是什么。
现在,为什么你的最后一个例子有效?
因为你说 greet 接收的是 AnotherThing 类型的对象,而不是像 T 这样的泛型类型。
AnotherThing
中的<AnotherThing extends AbstractThing>
与classAnotherThing
无关。它是类型参数的名称,就好像它被称为 T
一样。它表现得像 AbstractThing
的原因是因为我们只知道它是这样的。您的方法不知道它是如何参数化的;它所知道的是它得到了 AbstractThing
的子 class。这对于我们需要捕获类型的构造很有用,但我们不关心它是什么子类型,例如:
<T extends AbstractThing> void copy(List<T> from, List<T> to) {
for (T t : from) {
t.hello();
to.add(t);
}
}
但是如果你想要AbstractManager
的专门子class来管理AnotherThing
,类型参数应该在class,而不是方法:
public interface AbstractManager<T extends AbstractThing> {
// Operation that a things' manager must implement
public void greet(T t);
}
public class AnotherManager implements AbstractManager<AnotherThing> {
@Override
public void greet(AnotherThing t) {
t.hello();
t.goodbye();
}
}