添加泛型string object_3分钟带你彻底搞懂泛型背后的秘密

码个蛋(codeegg)第 751 次推文

作者:的一幕

原文:https://www.jianshu.com/p/dd34211f2565

这一节主要讲的内容是java中泛型的应用,通过该篇让大家更好地理解泛型,以及面试中经常说的泛型类型擦除是什么概念,今天就带着这几个问题一起看下:

举一个简单的例子:

609659ed0c609a235c59fc7a6e7a9dbb.png

这里可以看出来在代码编写阶段就已经报错了,不能往string类型的集合中添加int类型的数据。

那可不可以往List集合中添加多个类型的数据呢,答案是可以的,其实我们可以把list集合当成普通的类也是没问题的,那么就有下面的代码:

08372b3d5353a6bc3f0b28526b9fe9ee.png

从这里可以看出来,不定义泛型也是可以往集合中添加数据的,所以说 泛型只是一种类型的规范,在代码编写阶段起一种限制。

下面我们通过例子来介绍泛型背后数据是什么类型

public class BaseBean {
T value;
public T getValue {
return value;
}
public void setValue(T value) {
this.value = value;
}
}

上面定义了一个泛型的类,然后我们通过反射获取属性和getValue方法返回的数据类型:

03779cc897951e0cf9a1d8cfb00ef6dd.png c8ddcba09f66fc1003679f700a361dda.png

从日志上看到通过反射获取到的属性是Object类型的,在方法中返回的是string类型,因此咋们可以思考在getValue方法里面实际是做了个强转的动作,将object类型的value强转成string类型。是的,没错,因为泛型只是为了约束我们规范代码,而对于编译完之后的class交给虚拟机后,对于虚拟机它是没有泛型的说法的,所有的泛型在它看来都是object类型,因此泛型擦除是对于虚拟机而言的。

下面我们再来看一种泛型结构:

9450ebab1f787a7f98a3e05cc2f33301.png

这里我将泛型加了个关键字extends,对于泛型写得多的伙伴们来说,extends是约束了泛型是向下继承的,最后我们通过反射获取value的类型是String类型的,因此这里也不难看出,加extends关键字其实最终目的是约束泛型是属于哪一类的。所以我们在编写代码的时候如果没有向下兼容类型,会警告错误的:

109d3bb62893f28a4a8dee62e4662152.png

大家有没有想过为啥要用泛型呢,既然说了泛型其实对于jvm来说都是Object类型的,那咱们直接将类型定义成Object不就是的了,这种做法是可以,但是在拿到Object类型值之后,自己还得强转,因此泛型减少了代码的强转工作,而将这些工作交给了虚拟机。

比如下面我们没有定义泛型的例子:

f5bba29775aa282972f19df631c9fce5.png

势必在getValue的时候代码有个强转的过程,因此在能用泛型的时候,尽量用泛型来写,而且我认为一个好的架构师,业务的抽取是离不开泛型的定义。

常见的泛型主要有作用在普通类上面,

作用在抽象类、接口、静态或非静态方法上。

类上面的泛型

比如实际项目中,我们经常会遇到服务端返回的接口中都有errMsgstatus

等公共返回信息,而变动的数据结构是data信息,因此我们可以抽取公共的
BaseBean
public class BaseBean {
public String errMsg;
public T data;
public int status;
}

抽象类或接口上的泛型

//抽象类泛型
public abstract class BaseAdapter {
List DATAS;
}
//接口泛型
public interface Factory {
T create;
}
//方法泛型
public static T getData {
return ;
}

多元泛型

public interface Base {
void setKey(K k);
V getValue;
}

泛型二级抽象类或接口

public interface BaseCommon extends Base {
}
//或抽象类
public abstract class BaseCommon implements Base {
}

抽象里面包含抽象

public interface Base {
// void setKey(K k);
//
// V getValue;
void addNode(Map map);
Map getNode(int index);
}
public abstract class BaseCommon implements Base {
//多重泛型
LinkedList> DATAS = new LinkedList<>;
@Override
public void addNode(Map map) {
DATAS.addLast(map);
}
@Override
public Map getNode(int index) {
return DATAS.get(index);
}
}

>通配符

>通配符区别是>在你不知道泛型类型的时候,可以用>通配符来定义,下面通过一个例子来看看>的用处:

//定义了一个普通类
public class BaseBean {
T value;
public T getValue {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
//用来定义泛型的
public class Common1 extends Common {
}
048a6ed1d6632c333816c3dc562173b3.png

在定义的时候将Common的泛型指向Common1的泛型,可以看到直接提示有问题,这里可以想,虽然Common1是继承自Common的,但是并不代表BaseBean之间是等量的,在开篇也讲过,如果泛型传入的是什么类型,那么在BaseBean中的getValue返回的类型就是什么,因此可以想两个不同的泛型类肯定是不等价的,但是如果我这里写呢:

public static void main(String[] args) {
BaseBean commonBaseBean = new BaseBean<>;
//通配符定义就没有问题
BaseBean> common1BaseBean = commonBaseBean;
try {
//通过反射猜测setValue的参数是Object类型的
Method setValue = common1BaseBean.getClass.getDeclaredMethod("setValue
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值