Почему в этом случае метод переопределения не работает

1

извините за титул, так как я не мог найти лучшего, поэтому любые изменения на этом будут оценены.

рассмотрим эти классы:

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), потому что я должен выполнить сериализацию класса Dashlet с помощью jsonson mapper, и Джексон не может определить фактический тип и объект во время выполнения без дополнительной информации на суперклассах.

  • 0
    У меня точно такая же проблема
Теги:
oop
inheritance

3 ответа

2
Лучший ответ

Причина в том, что типы возврата могут быть ковариантными.

При переопределении метода вы всегда можете вернуть более конкретный тип (т.е. Подтип). Более понятным примером является следующее:

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> Collection<? extends GlobalDashletSetting>. См. Раздел о том, какие отношения супер-подтипов существуют между экземплярами родовых типов? в разделе Общие вопросы.

Для сеттера это не работает. Короче, почему он не работает: он не безопасен для типа. Пример того, где безопасность типа нарушается, легко найти, хотя это может показаться немного надуманным с первого взгляда:

// 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

Пример может показаться немного запутанным. Опять же, это более интуитивно понятно с "простыми" типами, такими как Number и Integer, но это сводится к одной и той же проблеме: если для метода setter был разрешен более специфичный тип, тогда безопасность типа может быть нарушена.

  • 0
    Благодарю. хотя @Pranalee ответил первым, но ваш ответ более полный
1

Потому что у него разные подписи.

Collection<DashletSetting> не является Collection<? extends GlobalDashletSetting> Collection<? extends GlobalDashletSetting>

вам необходимо переопределить точную подпись, а не ее часть.

если у вас есть метод, который принимает Object, вы не можете переопределить его с помощью метода, который принимает String даже String extends Object

в вашем случае, Collection<DashletSetting> и Collection<? extends GlobalDashletSetting> Collection<? extends GlobalDashletSetting> - фактически разные классы, вы должны переопределить их с тем же классом.

геттер работает, так как он имеет одну и ту же подпись (то же имя метода и без параметров), это не так в установщике

  • 0
    Это не объясняет, почему переопределение работает для получателя.
  • 0
    you need to override the exact signature, not part of it. не объясняет это? потому что так работает Java
Показать ещё 4 комментария
1

Поскольку метод overrided не может ограничивать объем входной переменной. Исходный метод может принимать все, что расширяет класс GlobalDashletSetting но, но метод overriden isrestricting только для одного подкласса класса GlobalDashletSetting

  • 0
    Как вы объясните поведение метода геттера с этим рассуждением?
  • 0
    начиная с Java 5 и выше, допускается co-variant возвращаемого типа метода при переопределении

Ещё вопросы

Сообщество Overcoder
Наверх
Меню