java 对泛型的理解_Java泛型理解

java泛型

通俗的讲,泛型就是操作类型的占位符

一、通常泛型的写法

1.1定义泛型类

public class ApiResult{

int resultCode;

String resultMsg;

T resultObject;

}

1.2定义泛型方法

public JsonUtil{

public T str2Json(String jsonText, Class target){

T result = null;

...

return result;

}

}

1.3 K,V类型

public class ResultMap{

private K key;

private V value;

// 省略set,get方法

public void put(K key, V value){

this.key = key;

this.value = value;

}

}

二、使用泛型类和方法

ApiResult result = new ApiResult();

result.setResultCode(0);

result.setResultMsg("success");

result.setResultObject(new User());

String userJsonText = "userJsonText";

User u = JsonUtil.str2Json(jsonText, User.class);

ResultMap resultMap = new ResultMap();

resultMap.put("currentUserKey", new User());

三、类型擦除

public class Operate{

public static void main(String[] args){

List names = new ArrayList();

names.add("Jack");

names.add("Tom");

for(String name:names){

System.out.println(name);

}

}

}

其对应的class文件反汇编以后,我们使用java-gui反编译.exe  查看编译之后的代码如下:

发现没有,根本没有 这一部分了。这个限制为String类型的泛型被“擦除”了。写代码的时候,泛型会做校验,类型不对应的,无法add,但是编译之后边去掉了泛型类型。

四、为什么要使用java泛型??

这里的泛型就相当于“约法三章”,先给你定好“规矩”,我这个List 就是用来操作String类型的,你插入Person对象就不行。说白了就是为了类型安全。所以其好处有:

4.1类型安全:

通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

4.2消除强制类型转换

//该代码不使用泛型:

List li = new ArrayList();

li.put(new Integer(3));

Integer i = (Integer) li.get(0);

//该代码使用泛型:

List li = new ArrayList();

li.put(new Integer(3));

Integer i = li.get(0);

public class Fruit {

}

public class Apple extends Fruit {

}

public class Plate {

private

T item;

public

Plate(T t){

item

= t;

}

public

T getItem() {

return

item;

}

public

void setItem(T item) {

this.item

= item;

}

}

public class TestGenericParadigm {

public

static void main(String[] args){

Plate

p = new Plate(new Apple()); // 编译不通过

Plate

p = new Plate(new Fruit());

}

}

为什么上面这个会出现编译不通过??

解释:苹果是水果,但是装苹果的盘子不是装水果的盘子

所以,就算容器里装的东西之间有继承关系,但容器之间是没有继承关系的

为了让泛型用起来更舒服,Sun的大脑袋们就想出了 extends T>和 super T>的办法,来让”水果盘子“和”苹果盘子“之间发生关系

什么是上界?

Plate

翻译成人话就是:一个能放水果以及一切是水果派生类的盘子。再直白点就是:啥水果都能放的盘子。这和我们人类的逻辑就比较接近了。Plate和Plate最大的区别就是:Plate是Plate以及Plate的基类。直接的好处就是,我们可以用“苹果盘子”给“水果盘子”赋值了。

Plate extends Fruit> p=new

Plate(new Apple());

如果把Fruit和Apple的例子再扩展一下

//Lev 1

class Food{}

//Lev 2

class Fruit extends Food{}

class Meat extends Food{}

//Lev 3

class Apple extends Fruit{}

class Banana extends Fruit{}

class Pork extends Meat{}

class Beef extends Meat{}

//Lev 4

class RedApple extends Apple{}

class GreenApple extends Apple{}

在这个体系中,上界通配符

Plate

Fruit> 覆盖下图中蓝色的区域

262a67dfe58f8aa4cabeb07bda79f392.png

什么是下界?

Plate

表达的就是相反的概念:一个能放水果以及一切是水果基类的盘子。Plate是Plate的基类,但不是Plate的基类。对应刚才那个例子,Plate覆盖下图中红色的区域。

96caaa7556a07712f917ed45a8675f87.png

上下界通配符的副作用

边界让Java不同泛型之间的转换更容易了。但不要忘记,这样的转换也有一定的副作用。那就是容器的部分功能可能失效。

还是以刚才的Plate为例。我们可以对盘子做两件事,往盘子里set()新东西,以及从盘子里get()东西。

public class TestGenericParadigm {

public

static void main(String[] args){

/*

* 上界通配符

* 不能存入任何元素

* 读出来的东西只能放在Fruit或它的基类中

*/

Plate

extends Fruit> p = new Plate(new Apple());

p.setItem(new

Fruit()); //Error

p.setItem(new

Apple()); //Error

Fruit

newFruit1 = p.getItem();

Object

newFruit2 = p.getItem();

Apple

new Fruit3 = p.getItem();//Error

}

}

原因是编译器只知道容器内是Fruit或者它的派生类,但具体是什么类型不知道

所以通配符>和类型参数的区别就在于,对编译器来说所有的T都代表同一种类型。比如下面这个泛型方法里,三个T都指代同一个类型,要么都是String,要么都是Integer。

但通配符>没有这种约束,Plate>单纯的就表示:盘子里放了一个东西,是什么我不知道

下界 super

T>不影响往里存,但往外取只能放在Object对象里

使用下界

super Fruit>会使从盘子里取东西的get(

)方法部分失效,只能存放到Object对象里。set( )方法正常。

/*

* 下界通配符

* 存入元素正常

* 读取的东西只能存放在Object中

*/

Plate

super Fruit> p1 = new Plate(new Fruit());

p1.setItem(new

Fruit());

p1.setItem(new

Apple());

Apple

newFruit4 = p1.getItem();//Error

Fruit

newFruit5 = p1.getItem();//Error

Object

newFruit6 = p1.getItem();

因为下界规定了元素的最小粒度的下限,实际上是放松了容器元素的类型控制。既然元素是Fruit的基类,那往里存粒度比Fruit小的都可以。但往外读取元素就费劲了,只有所有类的基类Object对象才能装下。但这样的话,元素的类型信息就全部丢失

PECS原则

最后看一下什么是PECS(Producer Extends Consumer Super)原则,已经很好理解了:

频繁往外读取内容的,适合用上界Extends。

经常往里插入的,适合用下界Super。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值