Java高级特性之泛型的基本详解与使用
发布时间:2021-12-05 15:25:32 所属栏目:教程 来源:互联网
导读:为什么要使用泛型? 在Java中增加泛型之前,泛型程序设计是用继承来实现的,例如ArrayList,只维护Object引用的数组: public class ArrayList{ private Object[] elementData; public Object get(int i){...} public void add(Object o){...} } 在这里有一个
为什么要使用泛型? 在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<String> list = new ArrayList<String>(); //在JAVASE 7以后的版本中,可以直接使用一下方法来声明了 ArrayList<String> list = new ArrayList<>();简单泛型类 public class Pair<T>{ 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<String> test1 = new Pair<>(); Pair<Integer> test2 = new Pair<>();泛型方法 public class test{ public static <T> T first(T...a){ //... } } 但是需要注意的是,下面这几种,并不是泛型方法,不要混淆 public class test<T>{ private T t; //这个不是,只是一个普通的成员的方法 public test(T t){ this.t = t; } //这个也不是,只是泛型类是形参 public void add(test<T> object){...} } 通配符 通配符是什么,为什么要使用通配符?试想一下,如果我们在一个方法中要传入的参数可能是一个类的子类,这该怎么办呢? public void test(Persion<Number> p){...} x.test(Intger); //错误 x.test(Double); 不妨自己在编译器上试一试,这里是识别不了的,泛型中这两个没有关联关系,so,可以使用通配符 public void test(List<? extends T>){...} 这样子类和父类就联系起来了,?是类型实参,不是类型形参 如果像上面这样使用,我们可以add元素进去吗?反着思考一下,一个父类派生出很多个子类,我们在实例化的时候,很可能new出来的不是一个东西,这可不行呀,要存就得存一种,哪有Int,float都存进去的道理,如果还不明白可以看看代码 List<? extends Person> = new ArrayList<Student>(); List<? extends Person> = new ArrayList<Teacher>(); 这样的话我们只能Get,并不能add,想要add那我们现在可以这样 public void test(List<? superT>){...} 如此之后,只能add,不能get,又是为什么呢,还是反着思考,既然我们能够add元素进去,但是每一个元素的实际类型不相同 List<? super Student> = new ArrayList<Student>(); List<? super Student> = new ArrayList<Person>(); 当我们想get到Student的时候,可能是一个Person类型,这个Person可能是个Teacher 说了这么多,终于到了类型擦除 类型擦除 在JVM中不存在什么泛型,只有基本的类,当我们定义了一个泛型类的时候 public class Node<T> { private T data; private Node<T> next; public Node(T data, Node<T> 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<T extneds Comparable<T>> { private T data; private Node<T> next; public Node(T data, Node<T> 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<Integer>().getClass(); Class c2 = new ArrayList<Double>().getClass(); System.out.println(c1 == c2); 最终会得到true的结果,这里可以联想到,泛型无法使用instanceof 2、桥方法的合成用来保持多态 public class Node<T> { 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<Integer> { 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、反射和泛型 反射允许你在运行时分析任意的对象,如果对象是泛型类的实例,关于泛型类型参数则得不到太多信息,因为它们会被擦除 (编辑:我爱故事小小网_铜陵站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |