无法使用有界通配符传递通用子 class 的内部 class

Unable to pass inner class of a generic subclass using bounded wildcard

免责声明:该问题包含使用rxjava库的代码,但问题与其无关。我提供所有需要的信息,让那些不熟悉该图书馆的人回答。

我有以下方法根据是否缓存某些数据来选择数据源:

public Observable<? extends MetricDataSource> createForOwners() {
    return Observable.defer(new Func0<Observable<? extends MetricDataSource>>() {
        @Override
        public Observable<? extends MetricDataSource> call() {
            if (ownersCache.isCached()) {
                return cacheMetricDataSource;
            } else {
                return androidApiMetricDataSource;
            }
        }
    });
}

编译失败,出现以下错误:

Error:(29, 26) error: method defer in class Observable<T#2> cannot be applied to given types;
required: Func0<Observable<T#1>>
found: <anonymous Func0<Observable<? extends MetricDataSource>>>
reason: cannot infer type-variable(s) T#1
(argument mismatch; <anonymous Func0<Observable<? extends MetricDataSource>>> cannot be converted to Func0<Observable<T#1>>)
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>defer(Func0<Observable<T#1>>)
T#2 extends Object declared in class Observable

Observable.defer的签名是:

public final static <T> Observable<T> defer(Func0<Observable<T>> observableFactory)

Func0 基本上包含一个 call() 方法,该方法 return 是一个泛型类型的对象:

public interface Func0<T> { T call(); }

数据源声明为:

private final Observable<AndroidApiMetricDataSource> androidApiMetricDataSource;
private final Observable<CacheMetricDataSource> cacheMetricDataSource;

那么,为什么会失败? defer 期待一个 Observable<T> 而我给它一个 Observable<? extends MetricDataSource>,它应该很适合 T.

编辑:如果我用当前class中的私有方法替换defer方法,然后将Observable<T>替换为T 在参数和 return 类型中,它编译。但是,我不得不使用原来的Observable方法。

所以,这种方式失败了:

private static <T> Observable<T> defer(Func0<Observable<T>> observableFactory) {
    return null;
}

它编译的这个:

private static <T> T defer(Func0<T> observableFactory) {
    return null;
}

你能试试这个吗?

public <T extends MetricDataSource> Observable<T> createForOwners() {
    return Observable.defer(new Func0<Observable<T>>() {
        @Override
        public Observable<T> call() {
        if (ownersCache.isCached()) {
            return cacheMetricDataSource;
        } else {
            return androidApiMetricDataSource;
        }
        }
    });
}

我不确定,但我猜这是因为如果您不将它绑定到 T,它会认为它引用了可能独立更改的不同类型,因此不相等。但不确定

好吧,如果我将数据源的声明从

更改为
private final Observable<AndroidApiMetricDataSource> androidApiMetricDataSource;
private final Observable<CacheMetricDataSource> cacheMetricDataSource;

private final Observable<MetricDataSource> androidApiMetricDataSource;
private final Observable<MetricDataSource> cacheMetricDataSource;

然后我可以将方法声明为

public Observable<MetricDataSource> createForOwners() {
    return Observable.defer(new Func0<Observable<MetricDataSource>>() {
        @Override
        public Observable<MetricDataSource> call() {
            if (ownersCache.isCached()) {
                return cacheMetricDataSource;
            } else {
                return androidApiMetricDataSource;
            }
        }
    });
}

现在它编译了,一如既往地返回一个 Observable<MetricDataSource>

(将 Func0 视为 Supplier,将 Observable 视为 Iterable,如果这会使问题更熟悉的话)

在这里,Func0 和 Observable 直观上是协变的;在 Java 中,它们应该几乎总是与通配符一起使用,否则迟早会出现问题。

defter的签名当然可以归咎于此

<T> Observable<T> defer(Func0<Observable<T>> observableFactory)

它本来可以更笼统,因为

<T> Observable<? extends T> defer(Func0<? extends Observable<? extends T>> observableFactory)

但这也导致了通配符地狱...我看不到通配符尖叫声中的类型。

相反,我们可以过着危险的生活,只省略通配符 - 当出现问题时,进行一些转换以解决它。在您的情况下,我们需要将 Observable<Subtype> 转换为 Observable<Supertype>。这显然是安全的,这样做没有罪恶感。