写点什么

泛型使用到原理,2020-2021 阿里巴巴安卓面试真题解析

用户头像
Android架构
关注
发布于: 1 小时前

然后我们看下使用:


public void test() {


String str = "test";


WrapperObject wrapper = new WrapperObject(str);


Object obj = wrapper.getContent();


// 获取长度,需要强转,mmp


int length = ((String) obj).length();


// 既然强转,那么随便转,很危险


int value = ((Integer) obj).intValue();


}


我们看到,虽然用 Object 解决了问题,但是使用起来很麻烦,而且很危险。那么有没有更好的解决方案呢,有!泛型!我们直接上代码:


// 传递泛型参数,T 只是标记,随便写。


public class WrapperObject<T> {


private T content;


public WrapperObject(T content) {


this.content = content;


}


public String prefixHello() {


return "Hello" + content;


}


public String suffixAndroid() {


return content + "Android";


}


public T getContent() {


return content;


}


}


好,我们来看用法:


public void test() {


String str = "test";


// 这里创建的时候,传入了类型


WrapperObject<String> wrapper = new WrapperObject<>(str);


// 那么返回的值 就是创建时传入的类型


String content = wrapper.getContent();


// 获取长度,不用强转了


int length = content.length();


// 这里会直接报错,不能把 String 转换为 Integer


int value = ((Integer) content).intValue();


}


修改过的代码,简单明了,而且用起来非常方便,我们直接将需要的类型传入,就像一个参数一样,获取的时候就是我们需要的类型,这就是类型参数化。


泛型的使用




我们可以将泛型理解为一个 大于一般类型,小于 Object 类型 的类型,比如,T 一定是 Object,但是 Object 不一定是 T,所以 T 小于 Object,String 或 Integer 可以是 T,但是 T 不一定是 String 或 Integer,所以 T 大于 String,所以可以简单的理解为:


一般类型 < 泛型 < Object 类型

1 泛型类和泛型接口

泛型类的使用很简单,比如上面我们创建的 WrapperObject 类就是泛型类,它有个特点,就是类名后面跟上一个用尖括号括起来的类型,当然可以有多个,比如:


public class Fuck<A, B, C> {


private A a;


private B b;


private C c;


}


泛型接口跟泛型类是一样的,因为接口也是类的一种,比如常见的 List,Map 接口:


public interface List<E> extends Co


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


llection<E> {


}


可以看到,泛型接口/类 也是可以继承的,跟一般类没啥区别。


我们常见的 ArrayList,HashMap 等,都是泛型类,而且都是容器类,所以叫泛型容器。

2 泛型方法

泛型方法也很简单,我们知道,方法就是个黑盒,入口就是参数,出口就是返回值,所以我们关注这两方面即可。


泛型作为参数


很简单,我们需要在返回类型之前添加尖括号括起来的类型,然后在参数列表就可以像一般类型一样的使用,比如:


public <T> void test(T t) {


}


public static <T> void test(T t) {


}


泛型作为返回值


跟参数一样,返回类型之前加上尖括号括起来的类型,然后返回类型改为泛型即可:


public <T> T test(T t) {


return t;


}


public static <T> T test(T t) {


return t;


}


泛型的界




我们知道,泛型是小于 Object 的,然后又是大于一般类型的,那么它肯定能表示一个范围,这个范围就是边界,简称为界。

1 泛型的上界

假如现在我们有个需求,定义一个函数,入参是两个 int 类型的值,返回两数之和,太简单了,我们直接写:


// 求两数之和


public int add(int a, int b) {


return a + b;


}


完事之后,突然来了个 float,怎么办,于是我们发现了问题: 不是只有 int 才有加法这个操作,其他的 float,double,long 等,凡是 Number 的子类都具有加法,于是我们扩大这个加法的作用对象,改为 Number,如下:


public Number add(Number a, Number b) {


return a + b; // 这是个模拟方法,实际是没有的


}


然后我们来使用它:


public void test() {


int a = 10;


int b = 20;


// 这一行报错: Number 不能赋值给 int。


int c = add(a, b);


}


那么我们直接将 Number 改成 T 可以吗,不行!因为 T 没有"加法"这操作,只有 Number 及其子类有加法,那么我们需要一个是 Number 的子类的泛型,这就等价于限制了泛型的上界,也就是指定了它爹,代码如下:


// 通过<T extends Number>来指定上界


public <T extends Number> T add(T a, T b) {


return a + b;


}


public void test() {


int a = 10;


int b = 20;


// 传入的是 int,返回的也是 int,并且因为传入的是 Number 的子类,所以能使用加法


int c = add(a, b);


}


泛型的上界可以为类,接口,甚至另一个泛型,也可以有多个泛型,比如:


public <E, T extends E> T add(T a, T b) {


}


这里需要注意一点,两个"泛型类"之间不具有继承关系,比如:Integer 是 Number 的子类,但是 List<Integer>不是 List<Number>的子类。因为 List<Integer>整体是一个类型。


通过以上例子,我们可以看到,泛型可以表示一种动态类型,也可以表示一个范围。

2 泛型的下界

泛型没有下界,没有下界,没有下界!如果要使用下界,可以使用通配符?,比如:


public void test(List<? super Integer> list) {


}


因为通配符是另一个知识点,这里不多废话。

3 泛型多边界

我们知道泛型可以指定上界,我们又知道泛型就等价于一般类型,一般类型可以继承一个父类,可以实现多个接口,那么泛型指定一个上界,可以看成是继承一个父类,那么可不可以再指定一个接口上界呢,可以!


public <T extends Number & Serializable> void test() {


}


我们可以指定一个类和多个接口,等价于 java 类的单继承和多实现。而且这里面有个规则,类一定要紧跟在 extends 后面,接口使用 &连接在后面。接口可以有多个,类只能有一个。比如:


// 错误,因为 Number 是类,需要紧跟在 extends 后面。


public <T extends Serializable & Number> void test() {


}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
泛型使用到原理,2020-2021阿里巴巴安卓面试真题解析