返回值

时间:2016-10-05 21:41:29

标签: java type-parameter

我试图将这个问题压缩到尽可能少的代码。

我已经定义了一个表结构,比如数据库表,下面是RowTable类。 Table基本上是Row的列表。我希望子类定义它们TableRow的特定风格,并且我希望编译器捕获不适当的尝试,将一种类型的行放入不兼容类型的表中。

抽象Agent类提供了一种方法来获取参数并返回一个采用T类行的表。我已经定义了三种方法来说明我遇到的问题。

FinalAgentFinalTableFinalRow类定义了AgentTableRow类的实现。最终,我想要的是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是否编译了?

我不妨问,有没有更好的方法来做我正在做的事情?

3 个答案:

答案 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