我正在努力使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。
答案 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();
,这是无法完成的。