为什么在这种情况下,重写Setter方法不起作用

时间:2014-09-02 07:36:55

标签: java oop inheritance

抱歉标题,因为我找不到更好的标题,所以任何编辑都将不胜感激。

考虑这些课程:

public interface GlobalDashlet {        
    public Collection<? extends GlobalDashletSetting> getSettings();    
    public void setSettings(Collection<? extends GlobalDashletSetting> settings);

}

public class Dashlet implements GlobalDashlet { 
    private Collection<DashletSetting> settings;
    public Collection<DashletSetting> getSettings(){
        return settings;
    }
    //This Wont Work
    public void setSettings(Collection<DashletSetting> settings) {
        this.settings = settings;
    }

    //This Will Work
    public Collection<DashletSetting> getSettings(){
       return settings;
    }
}


public class DashletSetting implements GlobalDashletSetting {
}

为什么覆盖setter方法(我的意思是我已经完成的方式)不能工作(dashlet类抱怨未实现的方法)但是重写getter方法有效吗?

我该如何解决?我需要能够实现setter方法(就像我覆盖getter方法的方式),因为我必须使用jackson mapper来对Dashlet类进行serillize,并且Jackson无法在运行时确定实际的类型和对象而无需其他信息超级课程。

3 个答案:

答案 0 :(得分:2)

原因是返回类型可能是covariant

在覆盖方法时,您始终可以返回更具体的类型(即子类型)。一个更易于理解的例子如下:

class NumberProvider {
    Number getNumber() { return 1.23; }
}

class IntegerProvider extends NumberProvider {

    // Returning a more specific type when overriding:
    @Override
    Integer getNumber() { return 42; }
}

Collection<DashletSetting>类型是Collection<? extends GlobalDashletSetting>的正确子类型。请参阅泛型常见问题解答中有关Which super-subtype relationships exist among instantiations of generic types?的部分。

对于setter,这不起作用。它不起作用的简短原因是:它不是类型安全的。很容易找到违反类型安全的地方的例子,虽然乍一看似乎有点做作:

// This is the interface as it was defined:
public interface GlobalDashlet {        
    public void setSettings(Collection<? extends GlobalDashletSetting> settings);
}

public class Dashlet implements GlobalDashlet { 
    // Assume this was working: 
    public void setSettings(Collection<DashletSetting> settings) {

        // Then you could add a "DashletSetting" here:
        settings.add(new DashletSetting());
    }
}

// But someone who CALLED this method may not have given it
// a Collection<DashletSetting>, but maybe a collection
// like Collection<SpecialGlobalDashletSetting>:
Collection<SpecialGlobalDashletSetting> settings = ...;
GlobalDashlet dashlet = new Dashlet();

// Based on the method signature that was defined in the interface,
// this would be possible:
dashlet.setSettings(settings);

// Now, the "settings" collection WOULD contain a simple "DashletSetting",
// although it should only contain "SpecialGlobalDashletSetting" instances
// This would cause a ClassCastException sooner or later

该示例可能看起来有点令人困惑。同样,对于NumberInteger等“简单”类型更直观,但它归结为同样的问题:如果 setter 允许更具体的类型方法,然后可能违反类型安全。

答案 1 :(得分:1)

因为它有不同的签名。

Collection<DashletSetting>不是Collection<? extends GlobalDashletSetting>

你需要覆盖确切的签名,而不是它的一部分。

如果您的方法需要Object,则无法使用String甚至String扩展Object

的方法覆盖它

在你的情况下,Collection<DashletSetting>Collection<? extends GlobalDashletSetting>实际上是不同的类,你必须覆盖同一个类。

getter正在工作,因为它具有相同的签名(相同的方法名称和没有参数),这不是setter中的情况

答案 2 :(得分:1)

因为覆盖方法不能限制输入变量的范围。原始方法可以接受扩展GlobalDashletSetting类的任何内容,但是,覆盖方法只限于GlobalDashletSetting类的一个子类