12

我正在尝试使 API 尽可能用户友好。

让我们:

class B extends A {}

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

现在这个

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

无效,必须强制转换:

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

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

我知道为什么 Java 在这种情况下需要重新输入。请不要解释setX()返回 A的答案。我知道。 我在问泛型是否可以解决这个问题。

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

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

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

此外,IIRC C++ 允许.

4

4 回答 4

14

我在这里复制了另一个问题的部分答案,解释了对所谓“自我类型”的渴望以及 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”作为约定来指示它的用途。

于 2013-06-16T23:25:11.687 回答
6

在 A 类中试试这个:

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

你可以像这样使用它

B b = new B().setX();
于 2014-06-18T14:19:11.247 回答
4

如果您真的不喜欢演员表,您可以B覆盖该方法

@Override
public B setX() {
    super.setX();
    return this;
}
于 2013-06-16T23:20:54.357 回答
1

问题是该方法setX()返回 class 的对象,A而您正试图将其写入 class 的对象B。它可以在不强制转换 ( ) 的情况下反之亦然A a = new B();,但是这样你必须强制转换它,因为该语句B b = new B().setX();类似于B b = new A();不能执行的语句。

于 2013-06-16T23:13:07.420 回答