避免编译泛型错误
我有这样的接口:避免编译泛型错误
public interface Inflatable {
Pump<? extends Inflatable> getPump();
}
该接口:
public Pump<T extends Inflatable> {
int readPressure(T thingToInflate);
}
现在这个类:
public class Preparer {
public <T extends Inflatable> void inflate(T thingToInflate) {
int pressure = thingToInflate.getPump().readPressure(thingToInflate);
}
}
不能编译,与此错误:
The method readPressure(capture#1-of ? extends Inflatable) in the type Pump is not applicable for the arguments (T)
这里有什么问题?变量thingToInflate
必须是Inflatable
(因为<T extends Inflatable>
,因为?)子类的实例,并且readPressure
方法被定义为需要Inflatable
的子类。
我知道这个特定的例子是人为的,但一般情况是,给定的T
一个实例,我不能然后传递该实例的方法,在出现在完全相同的方式来定义T
另一个类。我能解决这个问题吗?
由getPump
返回的Pump
可能不是Pump<T>
。它返回Pump<U>
,其中U
是延伸Inflatable
的东西。假设T
是U
的子类型并不安全。
我们假设有2个具体类实现Inflatable
:C1
和C2
。 getPump
可能会返回Pump<C1>
的实例。我们假设T
是C2
。 C2
类型的对象不是C1
的实例,因此它不能传递给readPressure
方法。
这就是为什么没有类型安全违规就无法“修复”它的原因。
这里是表明你正在尝试做错误的事情一个具体的例子:
class C1 implements Inflatable, Pump<C1> {
@Override
public Pump<? extends Inflatable> getPump() {
return this; // an instance of C1 which implements Pump<C1>
}
@Override
public int readPressure(C1 thingToInflate) {
return 0;
}
}
class C2 implements Inflatable {
@Override
public Pump<? extends Inflatable> getPump() {
return new C1(); // again, an instance of C1 which implements Pump<C1>
}
}
public class Preparer {
public <T extends Inflatable> void inflate(T thingToInflate) {
int pressure = thingToInflate.getPump().readPressure(thingToInflate);
// Let's assume that it were possible. What happens if one calls
// new Preparer().inflate(new C2())?
// new C2().getPump() returns an instance of C1 which implements Pump<C1>
// It's readPressure method expects an instance of C1. But T = C2, so
// the thingToInflate is not an instance of C1.
// If the compiler allowed this to happen, the type safety
// would be violated.
}
}
你能做的唯一的事情就是重新设计的接口。我不能告诉你一个确切的方法来解决它,因为我不知道你的代码试图完成什么。
当您编写一个返回类型为T的方法时,这并不意味着返回的事物不能是T的子类。它只是意味着类型是T就编译器而言。就好像该方法返回一个List,返回的是一个LinkedList或ArrayList或其他。
当你指定T为泛型类型扩展某些东西时,你会说编译时类型是一个类型范围,它可能是T或者它可能是任何扩展T的类型。并且没有办法知道什么该类型不使用instanceof之类的东西,然后进行投射,从而击败了使用泛型的目的。
指定一系列类型对方法参数有意义。如果我有一个方法需要T extends Animal的列表,则调用者可以传入狗列表或猫列表。在其他情况下,这没有帮助。
所以不要使用扩展/超类型的通配符作为返回类型。有有效的Java(第5章,第28项)说这句话的条目,引用:
Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code.
(该文本是因为它出现在书中粗体,它是不是我介绍了。)请注意,这句话在使用有界通配符的讨论中找到。如果你的客户使用的方法真的不在乎什么类型(例如从方法返回
Class<?>
)然后继续。
从给出的例子看来,'Pump'实际上不应该是通用的,因为你期望的用法表明'int readPressure(Inflatable)'。可能还会看到[PECS](https://*.com/q/2723397/2891664)。 – Radiodef