在RxJava的代码中,使用了大量的泛型,如果不熟悉的话,阅读源码非常的困难,比如非常核心的Observable类中,lift()方法代码:
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return new Observable<R>(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> o) {
try {
Subscriber<? super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
onSubscribe.call(st);
} catch (Throwable e) {
// localized capture of errors rather than it skipping all operators
// and ending up in the try/catch of the subscribe method which then
// prevents onErrorResumeNext and other similar approaches to error handling
Exceptions.throwIfFatal(e);
st.onError(e);
}
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// if the lift function failed all we can do is pass the error to the final Subscriber
// as we don't have the operator available to us
o.onError(e);
}
}
});
}
所以这里把Java的泛型相关的知识总结一下。
1. 什么是泛型
百度百科中的描述是:泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
Java语言引入泛型的好处是安全简单。
2.泛型的使用方式
泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法
2.1 泛型类
- 格式:public class 类名<泛型类型1,…>
- 注意:泛型类型必须是引用类型
看一个例子
// 泛型类:把泛型定义在类上
public class ObjectTool<T> {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
// 泛型类的测试
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool<String> ot = new ObjectTool<String>();
ot.setObj("demo1");
String s = ot.getObj();
System.out.println(s);
ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
ot2.setObj(2018);
Integer i = ot2.getObj();
System.out.println(i);
}
}
输出:
demo1
2018
2.2 泛型方法
- 格式:public <泛型类型> 返回类型 方法名(泛型类型 .)
看一个例子
public class ObjectPrint {
public <T> void show(T t) {
System.out.println(t);
}
}
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectPrint op = new ObjectPrint();
op.show("demo2");
op.show(2222);
op.show(true);
}
}
看下输出:
demo2
2222
true
2.3 泛型接口
- 格式:public interface 接口名<泛型类型1…>
看个例子:
/* * 泛型接口:把泛型定义在接口上 */
public interface Inter<T> {
public abstract void show(T t);
}
//实现类在实现接口的时候,我们会遇到两种情况
//第一种情况:已经知道是什么类型的了
public class InterImpl implements Inter<String> {
@Override
public void show(String t) {
System.out.println(t);
}
}
//第二种情况:还不知道是什么类型的
public class InterImpl<T> implements Inter<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
public class InterDemo {
public static void main(String[] args) {
// 第一种情况的测试
Inter<String> i = new InterImpl();
i.show("hello");
// 第二种情况的测试
Inter<String> i = new InterImpl<String>();
i.show("hello");
Inter<Integer> ii = new InterImpl<Integer>();
ii.show(100);
}
}
2.4 可变参数与泛型方法可以很好的共存
看一个例子
private static <T> List<T> makeList(T... args) {
List<T> result = new ArrayList<T>();
result.addAll(Arrays.asList(args));
return result;
}
public static void main(String[] args){
List<String> ls = makeList("A", "B", "C");
System.out.println(ls);
}
3.Java泛型边界问题(super和extends关键字)
Java泛型中的PECS原则
总结一下就是:
- 如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)
- 如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)
- 如果既要存又要取,那么就不要使用任何通配符。
看一下大神的化简的rx代码: Rxjava深入理解之自己动手编写Rxjava
// Observer.java
// 观察者
public interface Observer<T> {
void onUpdate(T t);
}
// ObservableSource.java
// 被观察者(主题)接口
public interface ObservableSource<T> {
void subscribe(Observer<? super T> observer);
}
// Observable.java
// 具体的被观察者(主题)
public class Observable<T> implements ObservableSource<T> {
private T t;
public Observable(T t) {
this.t = t;
}
@Override
public void subscribe(Observer<? super T> observer) {
// 调用订阅时,触发观察者更新
observer.onUpdate(t);
}
}
observer.onUpdate(t) 这个地方就类似于把T类型,放到observer的盘子里,所以命中了第二条规则,因此使用<? super T>,如果把这里的代码改成 extends,编译器是会报错的。
capture <? extends T> can not be apply to T
再回头看一下RxJava的代码,你会发现非常多的<? extends T>,这回就好理解了吧。简单看下文中最开头的lift()。非常类似与2.4中的列子。
<R> Observable<R> lift(final Operator<? extends R, ? super T> operator)
//<R>是泛型类型
//Observable<R> 是lift的返回值类型
//参数只有一个operator,它的类型是 Operator<? extends R, ? super T>
//T 是 public abstract class Observable<T> implements ObservableSource<T>中的类型
网友评论