Java泛型:使用此类型作为返回类型?

时间:2013-06-16 23:05:44

标签: java generics this setter

我正在努力使API尽可能用户友好。

我们有:

class B extends A {}

class A {
    A setX(){ ...; return this; }
}

现在这个

B b = new B().setX();

无效,必须投标:

B b = (B) new B().setX();

有没有办法在A中使用泛型来使编译器知道“this”类型并接受第一种方式 - 没有强制转换并且没有在使用的地方传递类型参数? (即不是new B<B>().setX(),那很难看。)

我知道为什么Java需要在这种情况下重新输入。请不要回答解释setX()返回A. 我知道。 我在问仿制药能否解决这个问题。

对于那些仍然想告诉我“这就是静态类型如何工作”以及“甚至泛型都无法帮助”的人,请考虑这个有效的Java代码:

Map<String, String> map = new HashMap(){{ put( "foo", new RuntimeException() );
String foo = map.get("foo");  // ClassCastException!!

因此,你可以看到泛型DO允许你在代码中没有出现实际类型转换的情况下获得CCE 这就是为什么我希望泛型允许摆脱显式类型转换的原因。

另外,IIRC C++ allows that

4 个答案:

答案 0 :(得分:13)

我在这里复制answer to another question的一部分,解释了对所谓的“自我类型”的渴望以及Java中的解决方法。

方法链接

而不是写

foo.doA();
foo.doB();

很多人宁愿写

foo.doA().doB();

不幸的是,该语言并不直接支持方法链接,即使它正在成为越来越受欢迎的功能。解决方法是让doA()返回foo。它有点脏但可以接受。

但是,如果foo位于类型层次结构中,则解决方法将被破坏

class Bar
    Bar doA()

class Foo extends Bar
    Foo doB();

foo.doA().doB(); // doesn't compile, since doA() returns Bar

所以有些人要求一种特殊的“自我类型”来解决这个问题。假设有一个关键字This来表示“自我类型”

class Bar
    This doA()

foo.doA().doB(); // works, doA() returns the type of foo, which is Foo

似乎方法链是“自我类型”的唯一用例,因此语言可能永远不会引入它(最好直接支持方法链接)

人们发现泛型提供了解决此问题的方法

class Bar<This>
    This doA()

class Foo extends Bar<Foo>

Foo has a method "Foo doA()", inherited from Bar<Foo>

这是A extends B<A>模式最常用的用例。这是一个孤立的解决方法/技巧。它在A和B之间的关系中没有添加语义。

限制This之类的

也是一种流行的做法
class Bar<This extends Bar<This>>

这是丑陋无用的,我强烈建议不要这样做。只需使用“This”作为约定来表明它的用途。

答案 1 :(得分:4)

如果你真的不喜欢演员,你可以让B覆盖方法

@Override
public B setX() {
    super.setX();
    return this;
}

答案 2 :(得分:4)

在A组中尝试:

public <T extends A> T setX() {
    return (T) this;
}

你可以像这样使用它

B b = new B().setX();

答案 3 :(得分:1)

问题是方法setX()返回类A的对象,并且您正在尝试将其写入类B的对象。反之亦然,无需强制转换(A a = new B();),但这样你必须强制转换它,因为语句B b = new B().setX();类似于B b = new A();,这是无法完成的。