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

92 篇文章 0 订阅
87 篇文章 0 订阅

我们看下使用:

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 解决了问题,但是使用起来很麻烦,而且很危险。那么有没有更好的解决方案呢,有!泛型!我们直接上代码: java学习交流:737251827

// 传递泛型参数,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 Collection<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() {

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值