使用公共方法
创建课程Car
public Car myself() {
return this;
}
有一个子类Ferrari
和一个包含foo
对象的变量Ferrari
。
最后,
Ferrari bar = foo.myself();
这会警告您,因为方法myself()
会返回Car
个对象,而不是预期的Ferrari
。
注意:我知道这个例子很愚蠢,因为你只是bar = foo
。这只是一个例子。
解决方案:
myself()
。{/ li>中的Ferrari
方法
Car
时,将Ferrari
对象投射到bar
对象。两种解决方案都有效,我对此感到满意。但是,当您有多个Car
子类时,第一个是不合需要的。我觉得一遍又一遍地覆盖一种方法会破坏继承它的意义。接下来,关于第二种解决方案,铸造并不漂亮。感觉很愚蠢 - 如果我的变量属于Ferrari
类型,那么Java是否能够在不警告我的情况下隐式投射它?毕竟,Java必须知道返回的对象可以转换为Ferrari
,不是吗?
还有其他解决方法吗?只是出于好奇 - 我可以忍受铸造东西,告诉Java应该是什么东西......
答案 0 :(得分:5)
此解决方案以Java库中更常用的方式使用泛型。
它有效并且您不必每次都转换结果,也不必覆盖每个子类中的myself
方法。
我相信这是唯一不需要覆盖或投射的解决方案。它确实要求每个子类使用自己的类型作为超类Car
的类型参数:class Ferrari extends Car<Ferrari>
class Car<X extends Car<X>> {
public X myself() {
return (X) this;
}
}
class Ferrari extends Car<Ferrari> {
}
然后按预期使用它:
Ferrari testarossa = new Ferrari().myself();
这个概念在Java标准库中也以这种或那种方式使用了几次:
<强> java.lang.Enum
强>
public abstract class Enum<E extends Enum<E>>
<强> java.util.Comparable
强>
public interface Comparable<T>
(当您实施类比时,您应该传递自己的类类型:class ShoeSize implements Comparable<ShoeSize>
)
方法链
对此也有很好的用处 - 有一种模式,有些人喜欢,允许方法链接。这是StringBuilder
的作用:new StringBuilder().append("a").append("b").toString()
。但是,支持方法链接的类通常很难进行子类化。使用上面概述的方法可以在这种情况下进行子类化。
答案 1 :(得分:2)
这还取决于您对foo
变量的了解程度。
如果你知道
Ferrari foo = new Ferrari();
然后是一个重写的方法,如
class Ferrari extends Car {
@Override
public Ferrari myself() {
return this;
}
}
允许你利用covaraince,你可以做
Ferrari foo = new Ferrari();
Ferrari bar = foo.myself();
虽然可能没有多少应用案例有意义:当你已经知道它是法拉利时,你可以写一下
Ferrari bar = foo;
当您只知道
时情况就不同了Car foo = new Ferrari();
然后你运气不好:你不再知道运行时类型了,无论如何你都要投。
(注意:当涉及自引用泛型类型时,这种带有更具体类型的this
重写方法具有真实的应用案例。这有时称为getThis trick)< / p>
关于你的陈述
感觉很傻 - 如果我的变量属于法拉利,那么Java不应该在没有警告我的情况下隐式地施放它吗?毕竟,Java必须知道返回的对象可以转换为法拉利,不是吗?
事实并非如此。没有人阻止你覆盖像
这样的方法class Ferrari extends Car {
@Override
public Car myself() {
return new Volkswagen();
}
}
然后演员表将不再有效
答案 2 :(得分:1)
子类可以覆盖基类方法,并且作为该合同的一部分表明它将返回特定类型。这为类的用户提供了清晰度,而期望用户知道返回的类型并相应地投射它不会。因此,覆盖更好。