我试图将这个问题压缩到尽可能少的代码。
我已经定义了一个表结构,比如数据库表,下面是Row
和Table
类。 Table
基本上是Row
的列表。我希望子类定义它们Table
和Row
的特定风格,并且我希望编译器捕获不适当的尝试,将一种类型的行放入不兼容类型的表中。
抽象Agent
类提供了一种方法来获取参数并返回一个采用T
类行的表。我已经定义了三种方法来说明我遇到的问题。
FinalAgent
,FinalTable
和FinalRow
类定义了Agent
,Table
和Row
类的实现。最终,我想要的是method2a
,它获取参数列表并返回类型为FinalTable
的表。
public abstract class Row {}
public abstract class Table<T extends Row> {}
public abstract class Agent {
public <T extends Row> Table<T> method1(List<String> parameter) {
return null;
}
public <T extends Row> Table<T> method2a(List<String> parameter) {
return null;
}
public <T extends Row> Table<T> method2b(String parameter) {
return null;
}
}
public class FinalRow extends Row {}
public class FinalTable extends Table<FinalRow> {}
public class FinalAgent extends Agent {
@Override
public <T extends Row> Table<T> method1(List<String> parameter) {
return null;
}
@Override
public FinalTable method2a(List<String> parameter) {
return null;
}
@Override
public FinalTable method2b(String parameter) {
return null;
}
}
在底部:
method1
FinalAgent
编译,但我必须编写Table<FinalRow> t1 = new FinalAgent().method1(null);
才能调用该方法。method2a
FinalAgent
我将返回类型更改为FinalTable
以反映我实际返回的内容(我想写FinalTable t2a = new FinalAgent().method2a(null);
),但编译器会产生错误: FinalAgent类型的方法method2a(List)必须覆盖或实现超类型方法 method3
我将参数从List
更改为String
。该方法编译好,但给我一个类型安全警告,我至少可以使用它。所以,最后,问题是:method2a
FinalAgent
中的method2b
编译错误A > B > C => A > C
是否编译了?
我不妨问,有没有更好的方法来做我正在做的事情?
答案 0 :(得分:8)
目前尚不清楚为什么要对方法进行参数化。您承诺返回Table<T>
,但由于类型擦除,您的方法无法在运行时识别T
。您可能希望参数化整个Agent
类:
public abstract class Agent<T extends Table<?>> {
public T method1(List<String> parameter) {
return null;
}
public T method2a(List<String> parameter) {
return null;
}
public T method2b(String parameter) {
return null;
}
}
public class FinalAgent extends Agent<FinalTable> {
@Override
public FinalTable method1(List<String> parameter) {
return null;
}
@Override
public FinalTable method2a(List<String> parameter) {
return null;
}
@Override
public FinalTable method2b(String parameter) {
return null;
}
}
至于你的初步问题,我无法理解method2b
上的差异或警告信息。
答案 1 :(得分:1)
在单个位置使用方法参数意味着通常不需要参数
使用Agent
中的方法,FinalAgent
编译正常:
public Table<? extends Row> method2a(List<String> parameter) {
return null;
}
public Table<? extends Row> method2b(String parameter) {
return null;
}
答案 2 :(得分:1)
这是原始类型的直接后果。
let s = str as? String ?? ""
仍然是一种通用方法:没问题。method1
不再是通用方法,而是覆盖method2b
中的方法:没有问题(但由于未经检查的转换,安全警告除外)Agent
不再是通用方法,但不会覆盖任何内容 method2a
看到 method2a
被声明为这样:
FinalAgent
但在public Table method2a(List parameter)
中定义如下:
FinalAgent
现在你卡住了。相同的擦除但未正确覆盖public FinalTable method2a(List<String> parameter)
这是一个简单的例子:
method2a
它提供public interface Foo
{
public void bar(List a);
}
public class FooChild implements Foo
{
@Override
public void bar(List<String> a)
{
}
}
The method bar(List<String>) of type FooChild must override or implement a supertype method
它提供public interface Foo
{
public void bar(List a);
}
public class FooChild implements Foo
{
public void bar(List<String> a)
{
}
}
另一个例子。这段代码很好编译:
Name clash: The method bar(List<String>) of type FooChild has the same erasure as bar(List) of type Foo but does not override it
这个没有:
public interface Foo
{
public void bar(List<String> a);
}
public class FooChild implements Foo
{
public void bar(List<String> a)
{
}
}
它提供public interface Foo
{
public <T> void bar(List<String> a);
}
public class FooChild implements Foo
{
public void bar(List<String> a)
{
}
}
只要Name clash: The method bar(List<String>) of type FooChild has the same erasure as bar(List<String>) of type Foo but does not override it
成为通用方法,就会看到原始类型,我们可以注意到同样的问题。
原始类型问题的另一个示例:Name clash when overriding method of generic class