2016-03-25 10 views
2

(Для целей этого поста, позволяет выделить java.util.Observable)Java Тип подстановочные знаки

Я экспериментировал вокруг с обобщениями, а затем шаблонными типами. Цель заключалась в создании универсального наблюдаемого кэш-памяти с дельтами, предоставляемыми наблюдателям. Там, где это начинает сходить с рельсов, я хотел разрешить использование более общих наблюдателей, чем тот, который указан в Observable, например. Observer<Object> или некоторые другие обычные суперклассы.

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

Так что, если мы начнем с простым интерфейсом наблюдателя:

public interface Observer<T> { 
    public void notifyChange(ChangeHolder<T> change); 
} 

и связанным с ним ChangeHolder, в полной реализации этого будет более сложным, предоставляя списки добавленных/обновленные/удаленных объектов, но это достаточно чтобы продемонстрировать этот вопрос

public interface ChangeHolder<T> { 
    T getChange(); 
} 

Так с наблюдателем, определенным, я попытался реализовать Observable абстрактного класса:

public abstract class Observable<T> { 
    private Set<Observer<? super T>> observers = new HashSet<>(); 

    public void addObserver(Observer<? super T> obs){ 
     observers.add(obs); 
    } 

    public void change(ChangeHolder<T> changes){ 
     for(Observer<? super T> obs : observers){ 
      obs.notifyChange(changes); 
     } 
    } 
} 

И с этим я мог бы определить некоторые кэши объектов, объявив что-то вроде class TreeCache extends ObservableCache<Tree> (с этого момента я буду использовать Tree как примерный класс, который будет использоваться как T, предположим, что это простое POJO, распространяющееся только от Объект) и передать ChangeHolder<Tree> объектам на TreeCache.change() при необходимости. К сожалению, компилятор не согласен:

The method notifyChange(ChangeHolder<capture#2-of ? super T>) in the type Observer<capture#2-of ? super T> is not applicable for the arguments (ChangeHolder<T>) 

Вот где мое понимание заканчивается.

Без класса ChangeHolder (если в моем методе notifyChange вместо этого использовался простой T), он отлично работает, так как вполне законно передавать Tree в Observer.notifyChange (Object).

Я сделал вывод, что я должен быть в состоянии сделать то же самое с ChangeHolder - ChangeHolder<T> должны удовлетворять notifyChange(ChangeHolder<? super T>) таким же образом, что T удовлетворяет notifyChange(? super T) но четко я-то недоразумение?

ответ

2

В подписи нет подстановочного знака notifyChange(ChangeHolder<T> change). Поэтому общий тип переданного аргумента должен точно соответствовать типовому типу экземпляра Observer.

Observer<? super T> означает Observer неизвестного типа, который является супертипом T. Так как общий тип obs не может точно соответствовать общему типу changes, метод notifyChange неприменим.

Есть два возможных исправлений:

  1. изменения подписи к notifyChange(ChangeHolder<? extends T> change) так, что метод работает на подтипы.
  2. Избавьтесь от подстановочных знаков везде, так что у вас есть только <T>.

Я предпочитаю решение 1, так как это хорошая идея для подписей как можно более общих.

+0

Спасибо за быстрый ответ. Глядя на ваше предложение №2 сначала, если я не ошибаюсь, избавляясь от подстановочных знаков, означает, что тип моих экземпляров Observer должен точно соответствовать типам, поэтому я не смог бы привязать 'Observer ' к ' Наблюдаемый '. –

+0

@StrangelyTyped Это правда. Это должно быть 1. в этом случае. Вы также можете изменить 'change' на' public void change (ChangeHolder changes) '. –

+0

Извините, новичок в SO, случайно отправил комментарий раньше, используя ваше предложение # 1 Я не могу прикрепить 'Observer ' к 'Observable ' потому что Object не будет удовлетворять '? расширяет T' и использует '? super T' дает 'notifyChange (ChangeHolder ) неприменим для ChangeHolder ' –

Смежные вопросы