类型安全泛型 Java 观察者编译时错误
Type safe generic Java observer compile time error
要求
我正在尝试编写 Observer
/ Observable
对 classes。我想参数化 Observer
以便可以进行类型安全的更新调用。想象一下这个版本:
class View implements Observer<Model> {
@Override
public void update(Model model) { render(model); } // no casting:)
}
而不是这个需要转换的版本:
class View implements Observer {
@Override
public void update(Object model) { render((Model) model); } // casting:(
}
尝试
这是我目前所拥有的。我的 Observer
界面:
public interface Observer<T extends Observable> {
public void update(T observable);
}
和我的 Observable
摘要 class:
import java.util.List;
public abstract class Observable {
private List<Observer<? extends Observable>> observers;
public Observable() {
System.out.println(this.getClass());
}
public void addObserver(Observer<? extends Observable> obs) {
observers.add(obs);
}
public void removeObserver(Observer<? extends Observable> obs) {
observers.remove(obs);
}
protected <E extends Observable> void updateObservers(E self) {
for (Observer<? extends Observable> obs : observers) {
obs.update(self); // <-------------------- COMPILER ERROR!!!
}
}
}
问题
标记为 "COMPILER ERROR" 的行与 .update()
有问题:
The method update(capture#4-of ? extends Observable) in the type Observer is not applicable for the arguments (E)
所以即使传递给update()
的self
参数是E extends Observable
类型,它不满足接口方法签名update(T observable);
where T extends Observable
.这是为什么?我真的希望它们兼容。
我可以解决这个问题以满足我的要求吗?
谢谢。
像下面这样更改观察者界面:
public interface Observer<T extends Observable> {
public <E extends Observable> void update(E observable);
}
Why is that? I really expected those to be compatible.
因为函数 public void update(T observable);
与 Observer<T extends Observable>
class 具有相同的通用参数 T
,这意味着它的参数类型应该与 T
的类型相同将调用 update()
函数的引用变量。
虽然,当您尝试使用通配符 ?
时,变量 obs
的类型是 Observer<? extends Observable>
,它可以是任何不同的 class 扩展 Observable
比方法参数的类型 E
.
Is there I can fix this to meet my requirements?
是的,使用Self Bound / Recursive Generics,一个具体的例子是Class Enum<E extends Enum<E>>
,要理解这个概念你可以看看另请参阅下面的部分。
因此,您的 Observable
将类似于:
import java.util.List;
public abstract class Observable<T extends Observable<T>> {
private List<Observer<T>> observers;
public Observable() {
System.out.println(this.getClass());
}
public void addObserver(Observer<T> obs) {
observers.add(obs);
}
public void removeObserver(Observer<T> obs) {
observers.remove(obs);
}
protected void updateObservers(T self) {
for (Observer<T> obs : observers) {
obs.update(self);
}
}
}
Observer
界面:
public interface Observer<T extends Observable<T>> {
public void update(T observable);
}
View
class:
class View implements Observer<Model> {
@Override
public void update(Model model) { render(model); }
}
假设您的 Model
class 应该是这样的:
public class Model extends Observable<Model>{
}
另请参阅:
- Java Enum definition
- Self-bounding generics
- Java - Interface extending itself
- What would be the use of accepting itself as type arguments in generics
问题
根据@hexafraction 的评论,
Observable 的观察者列表由 Observer 的 any subclass 参数化(通配符 <? extends Observer>
)。这不适用于 Observer<T extends Observable>
的 update(T observable)
方法,该方法期望 正是 观察者被参数化的 Observable 类型。
Here's a counterexample: class A extends Observable, class B extends Observable, class A1 extends A. The wildcard for obs would allow an Observer to be assigned to obs, and in that case calling obs.update() with an instance of A1 would be invalid.
解决方案
解决方案是也对 Observable class 进行参数化,以便为 Observer update()
方法正确约束列表内容:
public abstract class Observable<E> {
private List<Observer<E>> observers;
public Observable() {
observers = new ArrayList<>();
}
public void addObserver(Observer<E> obs) {
observers.add(obs);
}
public void removeObserver(Observer<E> obs) {
observers.remove(obs);
}
protected void updateObservers(E self) {
for (Observer<E> obs : observers) {
obs.update(self);
}
}
}
Observer 参数化为自己的 T
:
public interface Observer<T> {
public void update(T observable);
}
如果您需要类型约束,以便 Observers 可以 仅 观察 Observables,and/or Observables 可以 仅 发送 Observables 给 Observer更新,然后使用这些 class 签名:
public interface Observer<T extends Observable<T>> { ... }
public abstract class Observable<E extends Observable<E>> { ... }
class 主体和行为不受影响,但如果 Observers 和 Observables 没有绑定到彼此,编译器会报错。
用法
通过 Observable(模型)参数化观察者(视图):
class View implements Observer<Model> {
@Override
public void update(Model model) { render(model); } // no casting:)
}
单独参数化一个 Observable(模型)并调用 updateObservers()
:
class Model extends Observable<Model> {
public void doStuff() {
//...
updateObservers(this);
}
}
使用
导入 io.reactivex.Observable;
而不是
导入 java.util.Observable;
要求
我正在尝试编写 Observer
/ Observable
对 classes。我想参数化 Observer
以便可以进行类型安全的更新调用。想象一下这个版本:
class View implements Observer<Model> {
@Override
public void update(Model model) { render(model); } // no casting:)
}
而不是这个需要转换的版本:
class View implements Observer {
@Override
public void update(Object model) { render((Model) model); } // casting:(
}
尝试
这是我目前所拥有的。我的 Observer
界面:
public interface Observer<T extends Observable> {
public void update(T observable);
}
和我的 Observable
摘要 class:
import java.util.List;
public abstract class Observable {
private List<Observer<? extends Observable>> observers;
public Observable() {
System.out.println(this.getClass());
}
public void addObserver(Observer<? extends Observable> obs) {
observers.add(obs);
}
public void removeObserver(Observer<? extends Observable> obs) {
observers.remove(obs);
}
protected <E extends Observable> void updateObservers(E self) {
for (Observer<? extends Observable> obs : observers) {
obs.update(self); // <-------------------- COMPILER ERROR!!!
}
}
}
问题
标记为 "COMPILER ERROR" 的行与 .update()
有问题:
The method update(capture#4-of ? extends Observable) in the type Observer is not applicable for the arguments (E)
所以即使传递给update()
的self
参数是E extends Observable
类型,它不满足接口方法签名update(T observable);
where T extends Observable
.这是为什么?我真的希望它们兼容。
我可以解决这个问题以满足我的要求吗?
谢谢。
像下面这样更改观察者界面:
public interface Observer<T extends Observable> {
public <E extends Observable> void update(E observable);
}
Why is that? I really expected those to be compatible.
因为函数 public void update(T observable);
与 Observer<T extends Observable>
class 具有相同的通用参数 T
,这意味着它的参数类型应该与 T
的类型相同将调用 update()
函数的引用变量。
虽然,当您尝试使用通配符 ?
时,变量 obs
的类型是 Observer<? extends Observable>
,它可以是任何不同的 class 扩展 Observable
比方法参数的类型 E
.
Is there I can fix this to meet my requirements?
是的,使用Self Bound / Recursive Generics,一个具体的例子是Class Enum<E extends Enum<E>>
,要理解这个概念你可以看看另请参阅下面的部分。
因此,您的 Observable
将类似于:
import java.util.List;
public abstract class Observable<T extends Observable<T>> {
private List<Observer<T>> observers;
public Observable() {
System.out.println(this.getClass());
}
public void addObserver(Observer<T> obs) {
observers.add(obs);
}
public void removeObserver(Observer<T> obs) {
observers.remove(obs);
}
protected void updateObservers(T self) {
for (Observer<T> obs : observers) {
obs.update(self);
}
}
}
Observer
界面:
public interface Observer<T extends Observable<T>> {
public void update(T observable);
}
View
class:
class View implements Observer<Model> {
@Override
public void update(Model model) { render(model); }
}
假设您的 Model
class 应该是这样的:
public class Model extends Observable<Model>{
}
另请参阅:
- Java Enum definition
- Self-bounding generics
- Java - Interface extending itself
- What would be the use of accepting itself as type arguments in generics
问题
根据@hexafraction 的评论,
Observable 的观察者列表由 Observer 的 any subclass 参数化(通配符 <? extends Observer>
)。这不适用于 Observer<T extends Observable>
的 update(T observable)
方法,该方法期望 正是 观察者被参数化的 Observable 类型。
Here's a counterexample: class A extends Observable, class B extends Observable, class A1 extends A. The wildcard for obs would allow an Observer to be assigned to obs, and in that case calling obs.update() with an instance of A1 would be invalid.
解决方案
解决方案是也对 Observable class 进行参数化,以便为 Observer update()
方法正确约束列表内容:
public abstract class Observable<E> {
private List<Observer<E>> observers;
public Observable() {
observers = new ArrayList<>();
}
public void addObserver(Observer<E> obs) {
observers.add(obs);
}
public void removeObserver(Observer<E> obs) {
observers.remove(obs);
}
protected void updateObservers(E self) {
for (Observer<E> obs : observers) {
obs.update(self);
}
}
}
Observer 参数化为自己的 T
:
public interface Observer<T> {
public void update(T observable);
}
如果您需要类型约束,以便 Observers 可以 仅 观察 Observables,and/or Observables 可以 仅 发送 Observables 给 Observer更新,然后使用这些 class 签名:
public interface Observer<T extends Observable<T>> { ... }
public abstract class Observable<E extends Observable<E>> { ... }
class 主体和行为不受影响,但如果 Observers 和 Observables 没有绑定到彼此,编译器会报错。
用法
通过 Observable(模型)参数化观察者(视图):
class View implements Observer<Model> {
@Override
public void update(Model model) { render(model); } // no casting:)
}
单独参数化一个 Observable(模型)并调用 updateObservers()
:
class Model extends Observable<Model> {
public void doStuff() {
//...
updateObservers(this);
}
}
使用 导入 io.reactivex.Observable;
而不是 导入 java.util.Observable;