接下来这篇,我们学习泛型。前面文章,我们在创建集合对象的时候,如果不添加注解,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
d
2)自定义版本
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