RxJava操作符——Observable.lift 中的泛型原理深入剖析

前言

RxJava操作符——Observable.lift这篇文章中我们了解了lift()操作符的使用及深入了解其源码实现原理。

但是有没有人跟我一样在看源码的过程中被里面的泛型给绕晕了,包括泛型上限、泛型下限、泛型通配符、泛型接口的继承等等。

比如说下面的lift()方法的定义,参数list的第一个泛型为什么用泛型上限,第二个泛型又为什么用泛型下限?反过来可不可以?

public final <R> Observable<R> lift(final Operator<? extends R, ? super T> lift) {

}

本文的重点在于理解泛型通配符的上下限,这里说下我自己的理解:

定义通配符?前(可以先把该通配符理解成一个变量),要先确定该变量是要赋值给别人,还是接收别人的赋值:

  • 赋值给别人:那么要用?extends T,因为?继承T,T是父类,可以接收子类?,方法定义中?可作为返回值赋值给别人
  • 接收别人赋值:那么要用?super T,因为?是T的父类,所以可以接收子类T,方法定义中?可作为参数接收别人的传参

上面两条结论其实是基于另一个知识点,就是java中的多态,声明父类可以接收任一类型的子类

理解了上面两条结论再来看代码就比较好理解了

相关源码

这里先贴出lift()方法相关的源码,然后再对源码做解析,有删除了一些非相关的代码

public final <R> Observable<R> lift(final Operator<? extends R, ? super T> lift) {
    return new Observable<R>(new OnSubscribe<R>() {
        @Override
        public void call(Subscriber<? super R> o) {
            Subscriber<? super T> st = lift.call(o);
        }
    });
}
public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>> {

}
public interface Func1<T1, R> extends Function {
    public R call(T1 t1);
}
public interface Function {

}

单看接口的定义可以还不太容易理解接口定义的意图,再贴一个Operator接口的具体实现类OperatorMap

map()方法内部实现是调用lift()方法,重点研究下这个OperatorMap方法

public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
    return lift(new OperatorMap<T, R>(func));
}
public final class OperatorMap<T, R> implements Operator<R, T> {

    private final Func1<? super T, ? extends R> transformer;

    public OperatorMap(Func1<? super T, ? extends R> transformer) {
        this.transformer = transformer;
    }

    @Override
    public Subscriber<? super T> call(final Subscriber<? super R> o) {
        return new Subscriber<T>(o) {

            @Override
            public void onCompleted() {
                o.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                o.onError(e);
            }

            @Override
            public void onNext(T t) {
                try {
                    o.onNext(transformer.call(t));
                } catch (Throwable e) {
                    onError(OnErrorThrowable.addValueAsLastCause(e, t));
                }
            }

        };
    }

}

源码解析

接下来开始源码的分析,首先要明确下本文重点要解决的问题,为什么lift()方法的定义中,Operator的第一个泛型通配符哟啊定义成R上限,第二个泛型通配符要定义成T上限?

public final <R> Observable<R> lift(final Operator<? extends R, ? super T> lift) {

}

我们先看下第二个通配符'? super T'

? super T,根据我们上面前言的第二条结论,?是T的父类,所以?可以接收T类型的赋值,在方法定义中?可作为形参接收别人传入的值。接下来我们就看下Observable的具体实现类中是不是有定义了某个方法参数类型为'?'

先看下OperatorMap类的声明,需要注意的是此时OperatorMap中的T相当于lift()方法定义中Operator参数的第二个泛型'?',所以此T非彼T

public final class OperatorMap<T, R> implements Operator<R, T> {

}

然后再看下OperatorMap中的call方法,里面return了一个Subscriber,而这个Subscriber中的onNext方法接收的参数类型就是T,也即对应了lift()方法中的第二个'?',也验证了我们一开始的猜测——lift()中的第二个'?'是用于接收别人的传参的

接下来再来看lift()方法中Operator的第一个泛型'?'

'? extends R',根据我们上面前言中的第一条结论,通配符'?'是子类,可用于方法定义中的返回值,赋值给别人

我们就验证下在OperatorMap的实现中,有没有哪个方法返回了'?',然后赋值给别人,或者当做参数传给被人

再次说明下,lift()中Operator第一个'?'对应了OperatorMap类中R

public final class OperatorMap<T, R> implements Operator<R, T> {

}

我们主要看OperatorMap.call()方法中o.onNext(transformer.call(t))这一行代码,transformer.call()方法返回了R,赋值给o.next方法,验证了我们刚才的猜想——lift()中第一个'?'是用于将数据传给别人的

结语

看到这里可能有人被绕晕了,这很正常,我自己也晕了。本文只是作者本人研究RxJava的一篇笔记,仅供参考。如果真要理解泛型通配符的上下限建议看一些简单一点的例子,RxJava中的泛型实在是太绕了,一不小心就会把自己给绕晕了,反而打击自己的信心

发布了290 篇原创文章 · 获赞 51 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/mqdxiaoxiao/article/details/104535607