java 高级泛型_Java高级特性之泛型的基本介绍与使用

为什么要使用泛型?

在Java中增加泛型之前,泛型程序设计是用继承来实现的,例如ArrayList,只维护Object引用的数组:

public class ArrayList{

private Object[] elementData;

public Object get(int i){...}

public void add(Object o){...}

}

在这里有一个问题,就是每次使用的时候,都必须进行一次强制类型转换

ArrayList list = new ArrayList();

...

String name = (String)list.get(0);

可以发现还没有错误检查,如果是其他类型会检测不到,当添加的时候,可以是任何类的对象

每次都转换一次很麻烦,用什么解决呢,类型参数!

ArrayList list = new ArrayList();

//在JAVASE 7以后的版本中,可以直接使用一下方法来声明了

ArrayList list = new ArrayList<>();简单泛型类

public class Pair{

private T first;

private T second;

public Pair(){first = null; second = null;}

public Pair(T first, T second){this.first = first; this.second = second}

//get set

...

}

现在,我们可以像现在这样定义了

Pair test1 = new Pair<>();

Pair test2 = new Pair<>();泛型方法

public class test{

public static T first(T...a){

//...

}

}

但是需要注意的是,下面这几种,并不是泛型方法,不要混淆

public class test{

private T t;

//这个不是,只是一个普通的成员的方法

public test(T t){

this.t = t;

}

//这个也不是,只是泛型类是形参

public void add(test object){...}

}

通配符

通配符是什么,为什么要使用通配符?试想一下,如果我们在一个方法中要传入的参数可能是一个类的子类,这该怎么办呢?

public void test(Persion p){...}

x.test(Intger); //错误

x.test(Double);

不妨自己在编译器上试一试,这里是识别不了的,泛型中这两个没有关联关系,so,可以使用通配符

public void test(List extends T>){...}

这样子类和父类就联系起来了,?是类型实参,不是类型形参

如果像上面这样使用,我们可以add元素进去吗?反着思考一下,一个父类派生出很多个子类,我们在实例化的时候,很可能new出来的不是一个东西,这可不行呀,要存就得存一种,哪有Int,float都存进去的道理,如果还不明白可以看看代码

List extends Person> = new ArrayList();

List extends Person> = new ArrayList();

这样的话我们只能Get,并不能add,想要add那我们现在可以这样

public void test(List superT>){...}

如此之后,只能add,不能get,又是为什么呢,还是反着思考,既然我们能够add元素进去,但是每一个元素的实际类型不相同

List super Student> = new ArrayList();

List super Student> = new ArrayList();

当我们想get到Student的时候,可能是一个Person类型,这个Person可能是个Teacher

说了这么多,终于到了类型擦除

类型擦除

在JVM中不存在什么泛型,只有基本的类,当我们定义了一个泛型类的时候

public class Node {

private T data;

private Node next;

public Node(T data, Node next) {

this.data = data;

this.next = next;

}

// ...

}

在做完类型检查后,会变成这样

public class Node{

private Object data;

private Node next;

public Node(Object data, Node next) {

this.data = data;

this.next = next;

}

// ...

}

惊不惊喜意不意外!如果我们不想变成Object怎么办,可以自己设置

public class Node> {

private T data;

private Node next;

public Node(T data, Node next) {

this.data = data;

this.next = next;

}

// ...

}

public class Node {

private Comparable data;

private Node next;

public Node(Comparable data, Node next) {

this.data = data;

this.next = next;

}

// ...

}

看似其实就是这样嘛!但是这样的话会引起一些问题

1、不允许创建泛型数组

因为数组中的元素必须统一类型,如若使用了泛型数组,类型都被擦除成Object后,我们不会知道插入的数据是否都是同一个类型的,出错很难排查,可以运行一下下面的代码

Class c1 = new ArrayList().getClass();

Class c2 = new ArrayList().getClass();

System.out.println(c1 == c2);

最终会得到true的结果,这里可以联想到,泛型无法使用instanceof

2、桥方法的合成用来保持多态

public class Node {

public T data;

public Node(T data) { this.data = data; }

public void setData(T data) {

System.out.println("Node.setData");

this.data = data;

}

}

public class MyNode extends Node {

public MyNode(Integer data) { super(data); }

public void setData(Integer data) {

System.out.println("MyNode.setData");

super.setData(data);

}

}

类型擦除后

public class Node {

public Object data;

public Node(Object data) { this.data = data; }

public void setData(Object data) {

System.out.println("Node.setData");

this.data = data;

}

}

public class MyNode extends Node {

public MyNode(Integer data) { super(data); }

public void setData(Integer data) {

System.out.println("MyNode.setData");

super.setData(data);

}

MyNode mn = new MyNode(5);

Node n = mn;

n.setData("Hello");

实际上不是这样的,这会抛出ClassCastExeption,在哪里?

class MyNode extends Node {

// 桥方法

public void setData(Object data) {

setData((Integer) data);

}

public void setData(Integer data) {

System.out.println("MyNode.setData");

super.setData(data);

}

// ...

}

setData方法里面有一个强制类型转换,String没办法转换成Integer,记住一句话,桥方法被合成用来保持多态

3、反射和泛型

反射允许你在运行时分析任意的对象,如果对象是泛型类的实例,关于泛型类型参数则得不到太多信息,因为它们会被擦除

0b1331709591d260c1c78e86d0c51c18.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值