接下来这篇,我们学习泛型。前面文章,我们在创建集合对象的时候,如果不添加注解,IDE上就会有黄色的波浪线,学习了这篇之后,我们就会对泛型有一个基本了解和使用。

 

1.什么是泛型

打开API文档,搜索Collection,观察下面图片中红圈的尖括号就是泛型。

java 继承尖括号 java类后面加尖括号_java

      那么这个尖括号(泛型)是用来干嘛的呢?里面是表示参数类型是引用数据类型,例如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