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

Ond*_*žka 10 java generics setter this

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

让我们:

class B extends A {}

class A {
    A setX(){ ...; return this; }
}
Run Code Online (Sandbox Code Playgroud)

现在这个

B b = new B().setX();
Run Code Online (Sandbox Code Playgroud)

无效,必须铸造:

B b = (B) new B().setX();
Run Code Online (Sandbox Code Playgroud)

是否有一种方法使用泛型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!!
Run Code Online (Sandbox Code Playgroud)

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

此外,IIRC C++允许这样做.

Zho*_*gYu 13

我在这里将部分答案复制到另一个问题,解释了对所谓的"自我类型"的渴望以及Java中的解决方法.

方法链接

而不是写作

foo.doA();
foo.doB();
Run Code Online (Sandbox Code Playgroud)

很多人宁愿写作

foo.doA().doB();
Run Code Online (Sandbox Code Playgroud)

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

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

class Bar
    Bar doA()

class Foo extends Bar
    Foo doB();

foo.doA().doB(); // doesn't compile, since doA() returns Bar
Run Code Online (Sandbox Code Playgroud)

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

class Bar
    This doA()

foo.doA().doB(); // works, doA() returns the type of foo, which is Foo
Run Code Online (Sandbox Code Playgroud)

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

人们发现泛型为这个问题提供了一种解决方法

class Bar<This>
    This doA()

class Foo extends Bar<Foo>

Foo has a method "Foo doA()", inherited from Bar<Foo>
Run Code Online (Sandbox Code Playgroud)

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

这也是一个流行的做法,以约束This

class Bar<This extends Bar<This>>
Run Code Online (Sandbox Code Playgroud)

这是丑陋和无用的,我强烈建议反对它.只需使用"This"作为约定来表示它的用途.


小智 6

在 A 类中试试这个:

public <T extends A> T setX() {
    return (T) this;
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它

B b = new B().setX();
Run Code Online (Sandbox Code Playgroud)