本文共 3566 字,大约阅读时间需要 11 分钟。
JAVA泛型其实是类型的类型,比如List数组我们可以接受任意类型的元素存储在数组当中,也可以在定义数组时,指定集合当中只存储某一类型。可以说泛型给我们的程序代码提供了可扩展性。
关于泛型的声明,如何使用,这篇暂不介绍,我们从比较容易困惑的地方开始
举个例子如果我们定义了一个方法,接受List<Number> 类型的参数,那我们是否可以传递List<Integer>进去,答案是否定的
<? extend T> 表示的是当前泛型当中的元素,必须是T或者T类型的子类或者实现类
我们来看个例子,以下是三个类型的继承关系
class Fruit{}class Apple extends Fruit{}class Orange extends Fruit{}
public class Test { public static void main(String[] args) { Listapples = new ArrayList<>(); apples.add(new Apple()); List fruits = new ArrayList<>(); fruits.add(new Fruit()); Test.Transfer transfer = new Test.Transfer (); Fruit f1 = transfer.transfer(apples); Fruit f2 = transfer.transfer(fruits); } static class Transfer { T transfer(List list) { return list.get(0); } }}
这里我们给出了一个静态内部类,用来转化,传入的是List对象,获取到List当中的元素,因为List当中存放的元素都是T类型的子类,所以我们在返回值上设定为T,是没有问题的
但是有个新的问题,如果我们想往List<? extends Fruit>当中添加元素时,却不能添加成功
List fruits = new ArrayList(); fruits.add(new Fruit()) //编译不通过
原因在于,当我们往集合当中添加元素时,因为集合的声明是Fruit的子类,所以我们并不清楚是具体的那个子类,Apple或者是Fruit,这个时候编译器就会提示报错了,接下来就是关于泛型的另外一个使用方式了
public class Test { public static void main(String[] args) { Listfruits = new ArrayList<>(); List apples = new ArrayList<>(); Test.Transfer transfer = new Test.Transfer (); transfer.transfer(fruits,new Apple()); transfer.transfer(apples, new Apple()); } static class Transfer { void transfer(List list,T item) { list.add(item); } }}
基于以上方式实现,就可以在数组当中添加不同的类型
总结 extends 和 supper 一个是用来查询集合当中的元素,另一个是用来往集合当中添加元素
泛型当中如果我们定义的是Node<T> 那么编制出来的T就是Object, 如果是 ? extends List 那么编译出来就是List
1、JAVA当中不允许创建泛型类型的数组
Object[] list = new String[2]; list[0] = "abc"; list[1] = 123;
上面这段代码我们在编译时是没有问题的,但是当执行的时候,就会抛出类型转换异常,原因是String类型的数组不能存放整形
如果我们定义的集合是List[] list = new ArrayList<String>[];
但是在存放数据时,保存的是list[0] = new ArrayList<Integer>; list[1] = new ArrayList<String>; 因为java当中存在类型擦除,所以ArrayList<String> 和ArrayList<Integer> 是一样的!为了避免这种问题发生,所以就不允许创建泛型类型的数组。
2、对于泛型代码,JAVA编译器会生成一个bridge method
public class Node{ public T data; public Node(T data) { this.data = data; } public void setData(T data) { System.out.println("set Node data"); this.data = data; } public static void main(String[] args) { MyNode myNode = new MyNode(5); Node node = myNode; node.setData("adb"); //抛出异常 }}class MyNode extends Node { public MyNode(Integer data) { super(data); } public void setData(Integer data) { System.out.println("set myNode data"); super.data = data; }}
上面这段代码在编译时是可以的,但是运行时就会抛出异常错误,原因在于在MyNode方法当中编译时会生成一个BridgeMethod
class MyNode extends Node { // Bridge method generated by the compiler public void setData(Object data) { setData((Integer) data); } public void setData(Integer data) { System.out.println("MyNode.setData"); super.setData(data); } // ...}
这就是为什么不能转化String为Integer的原因
3、关于泛型使用instanceOf
我们无法对泛型代码直接使用instanceof ArrayList<Integer> 因为对编译器来说ArrayList<Integer>和ArrayList<String>是同一个类型,如果我们想判断是否为ArrayList的话,可以通过这种方式来调用
public static void rtti(List list) { if (list instanceof ArrayList ) { // OK; instanceof requires a reifiable type // ... }}以上就是关于泛型的一些内容,如有问题欢迎指正
转载地址:http://vlvti.baihongyu.com/