接下来这篇,我们学习泛型。前面文章,我们在创建集合对象的时候,如果不添加注解,IDE上就会有黄色的波浪线,学习了这篇之后,我们就会对泛型有一个基本了解和使用。
1.什么是泛型
打开API文档,搜索Collection,观察下面图片中红圈的尖括号就是泛型。
那么这个尖括号(泛型)是用来干嘛的呢?里面是表示参数类型是引用数据类型,例如String,和我们前面使用的Student,Person都是引用数据类型。主要起的作用是限定参数类型是某一个引用数据类型。如果加上了引用数据类型,就是该对象只能存储这个类型的引用数据类或者该类的子类对象。例如如何一个集合后面尖括号里面是Student,那么这个集合只能存储我们前面定义的自定义对象,即学生类。
2.泛型的好处
好处有两个:
1)提高了安全性(将运行期错误转换到编译区)
2)省去强制转换的麻烦
下面我们先来看看,不加泛型限定的集合,有什么麻烦出现。
先把需要用到的Student.java的代码贴出来。
package collection; public class Student { private String name; private int age; public Student() { super(); } public Student(String name, intage) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(intage) { this.age = age; } @Override public String toString() { return "Student [name="+ name+ ", age="+ age+ "]"; } }写一个没有限制参数类型的集合,在遍历代码块中,假如我们只想获取学生的姓名这个字段,结果会发现报错。
package generic; import java.util.ArrayList; import java.util.Iterator; import collection.Student; public class Demo1_Generic { public static void main(String[] args) { ArrayListlist= newArrayList(); list.add(100); list.add(true); list.add(new Student("张三",23)); Iteratorit = list.iterator(); while(it.hasNext()) { Studentp = (Student)it.next(); System.out.println(p.getName()); } } }运行异常:
Exception in thread "main" java.lang.ClassCastException:java.lang.Integer cannot be cast to collection.Student atgeneric.Demo1_Generic.main(Demo1_Generic.java:20)我们先在API 文档中搜索ClassCastException这个类,看看什么意思。可以看到这样的解释:当试图将对象强制转换为不是实例的子类时,抛出该异常。例如,我们想把一个猫类对象强制转换成狗类对象就会出现这个异常。
所以,上面代码,在集合没有限定引用类型,在编译代码的时候就通过没有报错,但是运行就报错。原因就是,我们集合中存储了Integer和Boolean以及Student三种类型的引用数据类型,但是后面遍历,我们写了强制转换代码,这里就会把Integer和Boolean强制转换成Student对象,就会发生强制转换异常。
下面写一个带上泛型的集合,例如我们下面限定集合内引用数据类型只能是Student对象。
package generic; import java.util.ArrayList; import java.util.Iterator; import collection.Student; public class Demo1_Generic { public static void main(String[] args) { ArrayList<Student>list= newArrayList<Student>(); //list.add(100); //list.add(true); list.add(new Student("张三",23)); Iterator<Student>it = list.iterator(); while(it.hasNext()) { Students = it.next(); //这里不用强制转换了 System.out.println(s.getName()); } } }上面集合类型限制了是Student,如果添加Integer或者Boolean就会编译报错,体现了提高安全性的特点,下面迭代器遍历不需要添加强转。
3.泛型特点和注意事项
1)尖括号里必须是引用数据类型
2)前后泛型限制类型必须一致,后面可以省略不写
3)限制类型最好不用Object
ArrayList<Student> list = newArrayList<Object>(); //前后不一致,编译出错 ArrayList<Student>list2= newArrayList(); //后面可以不写 ArrayList<Object>list3= newArrayList(); //最好不用Obect类型,相当于没有限制4.用泛型来写字符串和自定义集合练习
1)字符串版本
package generic; import java.util.ArrayList; import java.util.Iterator; import collection.Student; public class Demo1_Generic { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); Iterator<String> it = list.iterator(); //集合是什么类型,迭代器保持一样 while(it.hasNext()) { System.out.println(it.next()); } } }输出:
a b c d2)自定义版本
package generic; import java.util.ArrayList; import java.util.Iterator; import collection.Student; public class Demo1_Generic { public static void main(String[] args) { ArrayList<Student> list = new ArrayList<Student>(); list.add(new Student("张三",23)); list.add(new Student("李四",24)); list.add(new Student("王五",25)); Iterator<Student> it = list.iterator(); //集合是什么类型,迭代器保持一样 while(it.hasNext()) { Student s = it.next(); System.out.println(s.getName() + "..." +s.getAge()); } } }
运行输出:
张三...23李四...24王五...25
