假设我有这个基类:
abstract public class Base {
abstract public Map save();
abstract public void load(Map data);
}
令我惊讶的是,我可以在派生类中执行此操作:
public class Derived extends Base {
@Override
public Map<String, String> save() { //Works
...
}
...
}
但我不能这样做:
public class Derived extends Base {
@Override
public void load(Map<String, String> data) { // Fails
...
}
...
}
这里发生了什么?为什么我可以使用专门的返回类型而不是专门的参数类型?
更令人困惑的是,如果我保留load
的原始声明,我可以将它分配给更特殊的类型:
public class Derived extends Base {
@Override
public void load(Map data) {
Map<String, String> myData = data; // Works without further casting
...
}
...
}
答案 0 :(得分:11)
从专用类型到原始类型的隐式转换 - 始终是“安全的”,因为使用原始类型的人无法做出任何假设。因此,有人希望从方法中获得原始Map
,并不介意他们是否获得Map<String, String>
。
不是从原始类型到专用类型的隐式转换 - 如果有人将原始Map
传递到load
,它可能具有非字符串键和值。 load
的基本类型声明完全合法。
抛弃泛型,你的方法有点像这样:
public abstract class Base
{
public abstract Object save();
public abstract void load(Object x);
}
public class Derived extends Base
{
@Override
public String save() { ... } // Valid
@Override
public void load(String x) // Not valid
}
删除泛型后,为什么save
来电可以正常,但load
来电不是?考虑一下:
Base b = new Derived();
Object x = b.save(); // Fine - it might return a string
b.load (new Integer(0)); // Has to compile - but the override wouldn't work!
答案 1 :(得分:2)
您无法将参数更改为load(Map<String, String> data)
,因为如果您使用基类而不是专门的类,则可能会轻易违反此项:
Base base = new Derived()
base.load(new HashMap<Integer, Integer>());
这将调用派生的load-method但违反声明。由于只在编译时检查泛型,因此无法检测到该错误。
返回值没有问题,只要它们在子类中比在超类中更专业。
答案 2 :(得分:0)
我认为问题在于,一般来说,有两种方法可以通过参数类型进行区分。确切地说,需要选择一个。这需要查看未删除的类型。这意味着两种load
方法是可区分的。所以我们有可区分的方法,但是在擦除形式中只存在一种方法。
这不是返回类型的问题,因为(在Java中)您可以使用协变返回类型,但不能通过返回类型重载。