无法解决此Java泛型编译时警告

时间:2017-05-09 17:45:08

标签: java generics observer-pattern

请考虑以下代码:

public abstract class Subject {
    private Collection<Observer> observerCollection = new HashSet<>();
    // ...
    protected void notifyObservers() {
        this.observerCollection.stream().filter(Objects::nonNull).forEach(o -> o.update(this));
    }
}

public interface Observer<T extends Subject> {
    void update(T subject);
}

我收到以下编译时警告:

  

观察者是原始类型。对泛型类型Observer的引用应该参数化

     

类型安全:方法更新(主题)属于原始类型Observer。对泛型类型Observer的引用应该参数化

一个人来到了update,在我的生命中,我无法弄清楚如何在不使用警告抑制的情况下解决它。我已经尝试了几种方法来解决警告而没有运气。关于如何解决这个问题的任何想法?

动机

考虑以下客户端代码:

public class IntegerContainer extends Subject {
    private int integer;

    public IntegerContainer(int integer) {
        this.integer = integer;
    }

    public int getInteger() {
        return this.integer;
    } // ...
}

public class IntegerObserver implements Observer<IntegerContainer> {
    private int cachedInteger;

    @Override
    public void update(IntegerContainer subject) {
        this.cachedInteger = subject.getInteger(); // avoid cast here.
    } // ...
}

Observer中使用泛型的动机是避免对subject参数进行强制转换,以便观察者可以检索主题的状态。

2 个答案:

答案 0 :(得分:2)

这与流没有任何关系;它只是直接赢得了工作。

Observer<? extends Subject>或多或少无法使用,因为您不知道它是Subject的哪个子类型的观察者。如您所知,observerCollection仅包含Observer<SomeSubtypeOfSubjectThatNobodyEvenHeardOf>。 (请参阅PECS principle; Observer是消费者。)

我坦率地说,我认为没有任何类型安全的方法可以干净利落地执行此操作,因为您无法在Subject中说出附加的观察者都接受这个主题的子类型,因为没有办法引用&#34;这个主题的子类型。&#34;我能想到的最接近的黑客是

abstract class Subject<T extends Subject<T>> {
  private Collection<Observer<? super T>> observers;
  protected void notifyObservers() {
    this.observerCollection.stream().filter(Objects::nonNull).forEach(o -> o.update((T) this)); // yes, this cast is unchecked
  }
}

class SubSubject extends Subject<SubSubject> {
  ...
}

答案 1 :(得分:0)

我专注于SubjectObserver之间传递的价值。即这两个类都有一个类型参数,相关方法确保类型兼容:

public interface Observer<T> {
    void update(T value); // no subject, but a value
}

public class Subject<T> {
      private Collection<Observer<? super T>> observers = new HashSet<>();

      protected void notifyObservers() {
        this.observers.stream().filter(Objects::nonNull).forEach(o -> o.update(this.getValue()));
      }

      public void addObserver(Observer<T> observer) { // adding the right kind of observer
          observers.add(observer);
      }

      abstract public T getValue(); // returning the value - this one is abstract
}

上面的关键是abstract public T getValue();方法。您可以通过以下方式撰写IntegerContainerIntegerObserver

public class IntegerContainer extends Subject<Integer> {

    private int value;

    public IntegerContainer(int value) {
        this.value = value;
    }

    @Override
    public Integer getValue() {
        return value; // this is the parameter of the update() call
        // you could even compute here something
        // you can pass entire objects too, if required
    }

}

public class IntegerObserver implements Observer<Integer> {
    private int cachedInteger;

    @Override
    public void update(Integer value) {
        this.cachedInteger = value; // no cast here
    } // ...
}

你可以把它们放在一起:

IntegerContainer container = new IntegerContainer(3);
IntegerObserver observer = new IntegerObserver();
container.addObserver(observer);
container.notifyObservers();