文章目录

  • 1、概念
  • 2、好处
  • 3、泛型的定义与使用
  • 3.1、含有泛型的类
  • 3.2、含有泛型的方法
  • 3.3、含有泛型的接口
  • 4、泛型通配符
  • 5、通配符高级使用--受限泛型
  • 5.1、泛型的上限
  • 5.2、泛型的下限


集合中可以存放任意对象,只要把对象存储集合后,那么他们都会被提升为Object类型。当取出每一个对象,并且进行相应的操作,则必须进行类型转换。程序在运行时可能会发生java.lang.ClassCastException异常。
Collection虽然可以存储各种对象,但实际上通常Collection只存储同一类型对象。例如都是存储字符串对象。因此在JDK5之后,新增了泛型(Generic)语法,在设计API时可以指定类或方法支持泛型,这样使用API的时候也变得更为简洁,并得到了编译时期的语法检查。

1、概念

泛型是一种未知的数据类型。泛型也可以看作是一个变量,用来接收数据类型。创建集合对象是,会确定泛型的数据类型。如果集合不使用泛型,则默认是Object类型。

2、好处

  1. 将运行时期的ClassCastException,转移到了编译时期,变成了编译失败。
  2. 避免了类型强转的麻烦。

【弊端】泛型是什么类型,则集合就只能存储什么类型的数据。

3、泛型的定义与使用

3.1、含有泛型的类

  • 格式
修饰符 class 类名<代表泛型的变量> {
	//
}
  • 创建对象时确定泛型
  • 示例
// 自定义泛型类
public class Test23<E> {
    private E e;

    public E getE() {
        return e;
    }

    public void setE(E e) {
        this.e = e;
    }
}
// 调用
public class Test24 {
    public static void main(String[] args) {
        // 创建泛型为String的对象
        Test23<String> myObj = new Test23<>();
        // 调用setE
        myObj.setE("小学妹");
        // 调用getE
        String e = myObj.getE();
        System.out.println(e);

        // 创建泛型为Integer的对象
        Test23<Integer> myObj1 = new Test23<>();
        // 调用setE
        myObj1.setE(123);
        // 调用getE
        Integer e1 = myObj1.getE();
        System.out.println(e1);
    }
}

3.2、含有泛型的方法

  • 格式
修饰符 <代表泛型的变量> 返回值类型 方法名(参数列表) {
	// 
}
  • 调用方法时确定泛型,传递什么类型的参数,泛型就是什么类型
  • 示例
// 自定义泛型方法
public class Test25 {
    public <E> void show(E e) {
        System.out.println(e.getClass());
    }

    public <E> E show2(E e) {
        return e;
    }
}
// 调用
public class Test26 {
    public static void main(String[] args) {
        Test25 myObj = new Test25();

        myObj.show("hello");
        myObj.show(123);
        myObj.show(12.34);

        System.out.println(myObj.show2("hello"));
        System.out.println(myObj.show2(123));
        System.out.println(myObj.show2(12.34));
    }
}

3.3、含有泛型的接口

  • 格式
修饰符 interface 接口名<代表泛型的变量> {
	// 
}
  • 定义类时确定泛型
  • 始终不确定泛型,创建对象时确定泛型
  • 示例
// 定义泛型接口
public interface Test27<E> {
    public abstract void add(E e);
    
    public abstract E get();
}
// 创建类时确定泛型
public class Test28 implements Test27<String>  {
    @Override
    public void add(String s) {
        System.out.println(s);
    }

    @Override
    public String get() {
        return null;
    }
}
// 始终不确定泛型,创建对象时确定泛型
public class Test29<E> implements Test27<E> {
    @Override
    public void add(E e) {
        System.out.println(e.getClass());
    }

    @Override
    public E get() {
        return null;
    }
}

// 创建对象时确定泛型
public class Test30 {
    public static void main(String[] args) {
        Test29<String> myObj = new Test29<String>();
        myObj.add("hello");

        Test29<Integer> myObj1 = new Test29<Integer>();
        myObj1.add(123);
    }
}

4、泛型通配符

当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符表示。但是一旦使用泛型的通配 符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
【注意】

  1. 使用泛型通配符时,不能创建对象
  2. 使用泛型通配符时,只能作为方法的参数使用
  3. 泛型不存在继承关系
  • 示例
public static void main(String[] args) {
    Collection<Integer> list = new ArrayList<>();
    list.add(123);
    list.add(456);
    list.add(789);
    getEle(list);

    Collection<String> list1 = new ArrayList<>();
    list1.add("张三");
    list1.add("李四");
    list1.add("王五");
    getEle(list1);
}

private static void getEle(Collection<?> coll) {
    for (Object o : coll) {
        System.out.println(o);
    }
}

5、通配符高级使用–受限泛型

5.1、泛型的上限

  • 格式: <? extends E>
  • 含义:只能接受该类型及其子类

5.2、泛型的下限

  • 格式: <? super E>
  • 含义:只能接受该类型及其父类
public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<>();
    Collection<String> list2 = new ArrayList<>();
    Collection<Number> list3 = new ArrayList<>();
    Collection<Object> list4 = new ArrayList<>();

    getEle1(list1);
    getEle1(list2); // 编译报错
    getEle1(list3);
    getEle1(list4); // 编译报错

    getEle2(list1); // 编译报错
    getEle2(list2); // 编译报错
    getEle2(list3);
    getEle2(list4);
}

// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
private static void getEle1(Collection<? extends Number> list1) {
}

// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
private static void getEle2(Collection<? super Number> list1) {
}