无法使用有界通配符传递泛型子类的内部类

时间:2015-10-13 15:01:27

标签: java generics 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()方法:

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

数据源声明为:

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

那么,为什么会失败? defer期待Observable<T>并且我正在给它Observable<? extends MetricDataSource>,这应该与T完全吻合。

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

所以,这样就失败了:

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

它编译的这个:

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

3 个答案:

答案 0 :(得分:2)

你能尝试一下吗?

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,它会认为它引用了可能独立改变的不同类型,因此不相等。但不确定

答案 1 :(得分:1)

好吧,如果我从

更改数据源的声明,看起来就好了
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>

答案 2 :(得分:1)

(将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>。这显然是安全的,并且没有任何负罪感。