泛型的定义和作用
定义
把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
泛型,是java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
泛型是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。
作用
Java 语言中,引入泛型实乃为一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。具体作用是:
1. 类型安全
泛型的主要目标是提高 Java 程序的类型安全。编译时的强类型检查;通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。
2. 消除强制类型转换
泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
3. 潜在的性能收益
Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
4. 更好的代码复用性,比如实现泛型算法
在框架设计时候,BaseDao<T>、BaseService<T>、BaseDaoImpl<T>、BaseServiceImpl<T>;通过继承,实现抽象了所有公共方法,避免了每次都要写相同的代码。
设计原则
只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常。
使用场景
1. 集合
2. 泛型类
3. 泛型接口
4. 泛型方法
使用规则
1. 泛型的类型参数只能是类类型(包括自定义类),不可以是简单类型。
2. 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3. 泛型的类型参数可以有多个。
4. 泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。
5. 泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(Java.lang.String);
通配符与嵌套
通配符样式
常用的 T、E、K、V、?,本质上这些个都是通配符,没啥区别,只不过是编码时的一种约定俗成的东西。
T (type) 表示具体的一个java类型;
E (element) 代表Element;
K V (key value) 分别代表java键值中的Key Value;
?表示不确定的 java 类型。
通配符使用场景
用于声明变量或形参上,不能用在创建对象、泛型类 、泛型方法、泛型接口上。
?通配符
使用?号通配符的时候,**只能调对象与类型无关的方法,不能调用对象与类型有关的方法,因为直到外界使用才知道具体的类型是什么。
嵌套
泛型嵌套很常见,如:
List<Map<String,Integer>> list;
泛型上下边界
设定通配符上限
比如,想接收一个List集合,它只能操作数字类型的元素【Float、Integer、Double、Byte等数字类型都行】,此时我们需要用到设定通
配符上限带有子类限定的可以从泛型读取【也就是--->(? extend T)】
List<? extends Number>
设定通配符下限
当我们想要创建一个TreeSet<String>类型的变量的时候,并传入一个可以比较String大小的Comparator。那么这个Comparator的选择
就有很多了,它可以是Comparator<String>,还可以是类型参数是String的父类,比如说Comparator<Objcet>
带有超类限定的可以从泛型写入【也就是--->(? super T)】
<? super Type>
RxJava中的泛型使用分析
响应式编程
与我们传统编码(函数式编程)不一样,传统编码是做完这件事之后做另外一件事,给人的感觉都是单线程的,可能会开新线程去
处理耗时操作,在处理完成之后通过回调去处理之后的事情
而响应式编程提供给我们的是一种不一样的思想,在响应式编程的世界中一切执行流程都是基于事件的,已事件为驱动。
观察者模式
观察者模式是这样子的,我先举个例子看大家能不能理解
老师在讲台上讲课,而所有的学生都会观察着老师的一举一动,而老师每产生一个事件(比如说在黑板上写下一串公式),则对应着所有的学
生都观察到了老师的这一举动,自己则在自己的笔记本中记录,大脑中进行思考.而老师却不关心自己的学生对这一举动做什么事.
好了,例子就是这样的,我们来分析一下这个例子跟观察者模式有个什么关系?
这个例子中,老师可以产生事件,学生观察着老师,而老师在产生事件之后咳嗽一下,通知所有的学生,我刚才做了什么事,你们应该也需要做
点自己的事情,而这就产生了几个概念,观察者,被观察者,事件,事件的处理与消费
被观察者中存在观察者的引用,即教师知道自己要通知的学生都有谁
被观察者在产生事件之后通知观察者,即教师产生事件之后通知每一位观察着自己的学生。
RxJava
RxJava是对观察者模式的一种高级运用,或者说是一种升级,他把观察者模式具体化,更加明确了各个对象之间的关系。四个基本概念:
Observable (可观察者,即被观察者)、
Observer (观察者)、
subscribe (订阅)、事件。
Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
Type safety警告
举例看一下有没有什么问题
public class ImplObservable<T> implements Observable<T>{
T t;
public ImplObservable(T t){
this.t = t;
}
}
ImplObservable<Student> observer = new ImplObservable<>(new Student());
如果我把<>删除掉,则编译器会给我们这样一个警告
Type safety: The expression of type ImplObservable needs unchecked conversion to conform to ImplObservable<Student>
类型不安全。事情是这样的,在ImplObserver中,我们将泛型声明放在了类上,在该类中都可以识别T类型了,但是,构造方法接受一个T类型,如果你在创建该对象的时候,没有向该类声明T类型究竟属于哪种类型,就直接传递了一个实际类型过去,问题就像这样,教室接受所有类型过来,可能是教师,也可能是学生,但是,你在创建该教室的时候,你对教室接受的类型进行了限制,但是你又没有通知教室说教室准确的要接受哪种类型的对象, 这就会造成泛型不安全。
源码中Observable这个对象的构造函数的访问权限降低了,不在他包下都不可以创建这个对象,但是他提供了一个create方法去创建,我们也来
模仿一下
public class ImplObservable<T> implements Observable<T>{
T t;
private ImplObservable(T t){
this.t = t;
}
public static <T> Observable<T> create(T t) {
return new ImplObservable<T>(t);
}
}
创建方法变成了这样:
Observable<Student> create = ImplObservable.create(new Student());
案例一
需求
现在我给你一个student对象,你把这个对象给我通过某种规则给转换成teacher对象,你要给我返回的观察者不在是观察学生了,而是你
刚才转换成的teacher对象现在给一个student对象,要返回一个观察着student的观察者,我们通过上面的代码可以这样创建
ImplObservable.create(new Student());
现在要把这个学生通过某种规则转换成teacher
做一个接口回调,传递学生类型进去,返回老师类型,但是这俩类型不明确,应该用泛型
我们模仿Rxjava的命名,也叫作Func1,
public interface Func1<T,R> {
R call(T t);
}
接口做好了,我们现在要在Observer中去定义一个方法,将T类型转换成R类型,为了保持和Rxjava的一致,我们也叫作map
并且该方法要接受一种规则,一种能够将T转成R的规则
方法声明也有了
<R> Observer<R> map(Func1<T,R> fun1);
我们要在ImplObserver中去实现该方法了
@Override
public <R> Observer<R> map(Func1<T, R> fun1) {
// TODO Auto-generated method stub
Observer<R> ob = ImplObservable.create(fun1.call(t));
return ob;
}
案例二
需求
我需要在被观察者的执行过程中改一下被观察者中存在的对象的属性
并且不能破坏链式
我只是修改属性,我要的还是该被观察者
//声明下一步做的事
Observable<T> doOnNext(Action<T> action);
//定义泛型接口
public interface Action<T> {
void callAction(T t);
}
//实现doOnNext方法
@Override
public Observable<T> next(Action<T> action) {
action.callAction(t);
return this;
}
解释一下
当前被观察者中已经存在T对象的引用即t,只需要将t回调过去,在外部类中进行修改,
但是被观察者是不改变的,直接返回this就可以了.
Json解析泛型和Bean强转原理实践
json字符串
{
"message": "登录成功",
"code": "100",
"data": [
{
"sex": "女",
"phone": "15528883251",
"area": "成都",
"signName": "二哈",
"age": "18",
"userIcon": "https://f10.baidu.com/it/u=3661269061,116126203&fm=72",
"realName": "樱井莉亚",
"userInfoID": 9
}
]
}
基础数据bean
public class BaseResponseBean<T> {
public String message;
public String code;
public T data;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}}
实际数据bean
public class LoginUser {
private String sex;
private String phone;
private String area;
private String signName;
private int age;
private String userIcon;
private String realName;
private Long userInfoID;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getSignName() {
return signName;
}
public void setSignName(String signName) {
this.signName = signName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getUserIcon() {
return userIcon;
}
public void setUserIcon(String userIcon) {
this.userIcon = userIcon;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public Long getUserInfoID() {
return userInfoID;
}
public void setUserInfoID(Long userInfoID) {
this.userInfoID = userInfoID;
}}
使用方式
Type jsonType = new TypeToken<BaseResponseBean<LoginUser>>() {}.getType();
BaseResponseBean<LoginUser> bean = new Gson().fromJson(response, jsonType);
baseresponse为需要解析的json字符串,而bean.getData()就是为LoginUser的实例对象.