如何在Java 8中使用子类进行方法链接
我遵循this pattern实现了Java中的子类方法链接。我们的目标是,我有一个父类的方法,但可以分配的子类,如:如何在Java 8中使用子类进行方法链接
interface Screen {
<T extends Screen> T setBrightness(int value);
<T extends Screen> T setContrast(int value);
}
class CrtScreen implements Screen {
@SuppressWarnings("unchecked")
@Override
public <T extends Screen> T setBrightness(int value) {
// ...
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public <T extends Screen> T setContrast(int value) {
// ...
return (T) this;
}
}
class ColorCrt extends CrtScreen { /* ... */ }
public static void main(String[] args) {
ColorCrt cc = new ColorCrt().setBrightness(50).setContrast(50);
}
现在我也有,我想我的对象添加到容器对象,如:
class Stuff {
Stuff add(Screen s) {
// ...
return this;
}
Stuff add(String s) {
// ...
return this;
}
Stuff add(int i) {
// ...
return this;
}
}
public static void main(String[] args) {
new Stuff().add(new ColorCrt().setBrightness(50).setContrast(50)).add(25).add("...");
}
这现在不再适用于Java 8,给我方法add(Screen)对于类型Stuff不明确。我明白原因为explained here。我只看到两个选项的时刻:
我不使用
<T extends
,只是Screen setBrightness(value)
。它使我可以选择将我的实现类分配给相应的变量,并且当我想执行特定于实现的方法时,我必须将其转换。我必须在我的方法链接中添加强制类型或类型参数。这是非常难看 阅读并很难解决的大结构(拳击的多个级别),而必须从Java 7
移植有没有在Java中实现8让我方法链接的方式仍然有两个功能?如果没有,这两种方法中的一种可以被认为更有意义吗?
在您的代码:
class CrtScreen implements Screen {
@SuppressWarnings("unchecked")
@Override
public <T extends Screen> T setBrightness(int value) {
// ...
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public <T extends Screen> T setContrast(int value) {
// ...
return (T) this;
}
}
你的成员函数setContrast和setBrightness不需要是通用的,如果它是通用的,你需要指定类型是什么(在调用点)。我用这个办法,而使得界面通用的,这意味着这些方法need'nt是:
interface Screen<T extends Screen> {
T setBrightness(int value);
T setContrast(int value);
}
class CrtScreen implements Screen<CrtScreen> {
@SuppressWarnings("unchecked")
@Override
public CrtScreen setBrightness(int value) {
// ...
return this;
}
@SuppressWarnings("unchecked")
@Override
public CrtScreen setContrast(int value) {
// ...
return this;
}
}
如果你想继续做你的方式,你就需要指定其类型适用于通用(见下图):
public static void main(String[] args) {
new Stuff()
.add(new ColorCrt().<ColorCrt>setBrightness(50))
.add(25).add("...");
}
这正是我所描述的。您的第一个建议不适用于像ColorCrt cc = new ColorCrt()。setBrightness(50)这样的分配。setContrast(50);'-error是*类型不匹配:不能从CrtScreen转换为ColorCrt *。第二种方法有效,但写起来很难看。我正在寻找的是解决这两个问题的解决方案,允许分配子类*和*方法链*而不需要在任何地方指定类型。也许这需要一个完全不同的方法。 – Paramaeleon
CrtScreen是ColorCrt的基础,因此Color ...可以转换(与多态兼容)到CrtScreen,但不是反过来 - 这是有目的的。转换为基础时可以执行分配,但不能派生。在这两种情况下,它们都与屏幕(全部基础)多态兼容,这正是您想要的。我不确定你想要做什么。也许你应该发布更多的代码,因为在我看来,我发布的代码已经足够了 –
@Paramaeleon,除此之外,我认为在这种情况下你根本不需要泛型。您的基地应该通过其界面为您提供所有必需的功能,否则您会误解多态性。 –
最后我发现,通过使interface
的abstract class
对我工作的解决方案。这似乎足以满足Java 8编译器的要求。
概念证明:
static abstract class Screen {
abstract <T extends Screen> T setBrightness(int value);
abstract <T extends Screen> T setContrast(int value);
}
static class CrtScreen extends Screen {
@SuppressWarnings("unchecked")
@Override
public <T extends Screen> T setBrightness(int value) {
// ...
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public <T extends Screen> T setContrast(int value) {
// ...
return (T) this;
}
}
static class ColorCrt extends CrtScreen { /* ... */ }
static class Stuff {
Stuff add(Screen s) {
return this;
}
Stuff add(String s) {
return this;
}
Stuff add(int i) {
return this;
}
}
public static void main(String[] args) {
ColorCrt cc = new ColorCrt().setBrightness(50).setContrast(50);
new Stuff().add(new ColorCrt().setBrightness(50).setContrast(50)).add(25).add("...");
}
这是一个破碎的通用结构。只要考虑'ColorCrt cc = new CrtScreen()。setBrightness(0);',现在编译时没有任何错误,但显然会在运行时失败。这就是为什么你得到这些* unchecked *警告你压制。 – Holger
为什么不依赖协变返回类型?例如,看看'StringBuilder'如何实现'Appendable'。 –
什么'类屏幕 {'? –
我不明白为什么'添加(屏幕)'应该是模棱两可的。 – lexicore
@lexicore ...因为'String'的子类(假设'String'不会是'final')可能实现'interface Screen'。在编译时,编译并不知道运行时的对象是否可以是这样的子类。 (编译器不关心那个'String'实际上不能被继承,因为它是'final'。)参见:https://stackoverflow.com/q/28466925/1503237 – Paramaeleon