1 基本概述

  • 泛型的本质就是”参数化类型”。一提到参数,最熟悉的就是定义方法的时候需要形参,调用方法的时候,需要传递实参。那”参数化类型”就是将原来具体的类型参数化
  • 泛型的出现避免了强转的操作,在编译器完成类型转化,也就避免了运行的错误。

    2 泛型的目的

  • Java泛型也是一种语法糖,在编译阶段完成类型的转换的工作,避免在运行时强制类型转换而出现ClassCastException,类型转化异常。


    3、实例

    随着JDK 1.5时 增加了泛型

3.1、不使用泛型

  1. public static void main(String[] args){
  2. List list = new ArrayList();
  3. list.add(11);
  4. list.add("哈哈");
  5. for (int i = 0 ; i < list.size(); i++) {
  6. System.out.println((String)list.get(i));
  7. }
  8. }

运行结果:
image.png
因为list类型是Object。所以int,String类型的数据都是可以放入的,也是都可以取出的。但是上述的代码,运行的时候就会抛出类型转化异常.

3.2、使用泛型

  1. public static void main(String[] args){
  2. List<String> list = new ArrayList();
  3. list.add(11);
  4. list.add("哈哈");
  5. for(int i = 0;i<list.size();i++){
  6. Systerm.out.println((String)list.get(i));
  7. }
  8. }

从代码中看出,集合只能添加String类型的。

4、泛型的三种使用

4.1、泛型类

  1. public class 类名 <泛型类型1,...> {
  2. }

泛型类型必须是引用类型(非基本数据类型)

4.2、泛型方法

  1. public <泛型类型> 返回类型 方法名(泛型类型 变量名) {
  2. }
  • 注意要点:

    • 方法声明中定义的形参只能在该方法里使用,而接口、类声明中定义的类型形参则可以在整个接口、类中使用。当调用fun()方法时,根据传入的实际对象,编译器就会判断出类型形参T所代表的实际类型。 ```java public class FanDemo {

      //定义方法 public T fun(T t){ // 可以接收任意类型的数据
      return t; // 直接把参数返回
      }

      public static void main(String[] args) { FanDemo f = new FanDemo(); String str = f.fun(“嘿嘿”); System.out.println(str); int i = f.fun(10); System.out.println(i); }

}

  1. <a name="GAqC9"></a>
  2. #### 4.3、泛型接口
  3. ```java
  4. public interface 接口名<泛型类型> {
  5. }

实例:
为Element的首字母,一般表示集合中的元素。
E一般用来表示集合类型中的元素的类型,例如List接口的定义,public interface List extends Collection
为Type的首字母,表示传输参数的类型。

  • E——Element 表示元素 特性是一种枚举
  • T——Type 类,是指Java类型
  • K—— Key 键
  • V——Value 值
  • ?——在使用中表示不确定类型

    1. /**
    2. * 泛型接口的定义格式: 修饰符 interface 接口名<数据类型> {}
    3. */
    4. public interface Inter<T> {
    5. public abstract void show(T t) ;
    6. }
    1. public class InterImpl<E> implements Inter<E> {
    2. @Override
    3. public void show(E e) {
    4. System.out.println(e);
    5. }
    6. public static void main(String[] args) {
    7. Inter<String> inter = new InterImpl<String>();
    8. inter.show("hello");
    9. }
    10. }

4.4、源码中泛型的使用,List接口和ArrayList类的代码片段

  1. //定义接口时指定了一个类型形参,该形参名为E
  2. public interface List<E> extends Collection<E> {
  3. //在该接口里,E可以作为类型使用
  4. public E get(int index) {}
  5. public void add(E e) {}
  6. }
  7. //定义类时指定了一个类型形参,该形参名为E
  8. public class ArrayList<E> extends AbstractList<E> implements List<E> {
  9. //在该类里,E可以作为类型使用
  10. public void set(E e) {
  11. .......................
  12. }
  13. }

5、高级通配符

5.1、上界通配符

<? extends T>表示的是类型的上界【包含自身】,因此通配的参数化类型可能是T或T的子类。

  1. 它表示集合中的所有元素都是Animal类型或者其子类
  2. List<? extends Animal>

这就是所谓的上限通配符,使用关键字extends来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身。

  1. 这样就确定集合中元素的类型,虽然不确定具体的类型,但最起码知道其父类。然后进行其他操作。
  2. //Cat是其子类
  3. List<? extends Animal> list = new ArrayList<Cat>();

5.2、下界通配符

下界通配符<? super T>表示的是参数化类型是T的超类型(包含自身),层层至上,直至Object

  1. 它表示集合中的所有元素都是Cat类型或者其父类
  2. List <? super Cat>

这就是所谓的下限通配符,使用关键字super来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身

  1. //Animal是其父类
  2. List<? super Cat> list = new ArrayList<Animal>();

5.3、无界通配符

  • 任意类型,如果没有明确,那么就是Object以及任意的Java类了
  • 无界通配符用<?>表示,?代表了任何的一种类型,能代表任何一种类型的只有null(Object本身也算是一种类型,但却不能代表任何一种类型,所以List和List的含义是不同的,前者类型是Object,也就是继承树的最上层,而后者的类型完全是未知的)