泛型目录

  • 泛型概述
  • 什么时候使用泛型
  • 泛型在集合中的应用
  • 泛型在类中的使用
  • 泛型在方法中的应用
  • 泛型在接口中的应用
  • 泛型的通配符:? 未知类型
  • 泛型范围


泛型概述

  • Java 1.5v 之后出现的安全机制。
  • 将运行时期的问题提前暴露在编译时期
  • 避免了强制转换中书写的凌乱代码
  • 提高编译时期的安全性
  • 翻译用于编译时期,运行时,将会去掉泛型,生成的class文件中是不带泛型的,这个称之为泛型的擦除
  • 泛型擦除,是为了兼容运行时的类加载器。因为泛型是JDK1.5加入的,如果没有擦除,则表示类加载器也需要升级。
  • 类型的补偿,在运行时,通过获取元素的类型进行强制转换动作,不需要程序员强制转换,这是因为在编译时,类型被擦除,所以类型转换的过程称之为类型补偿。
  • 泛型中不能出现基本类型eg:

什么时候使用泛型

  • 当操作的引用数据类型不确定的时候,就使用<>将要操作的引用数据类型传入即可。
  • 泛型<>是一个用于接收具体引用数据类型的参数范围。
  • 只要用到了带有<>的类和接口,就需要明确数据类型。而且< E >中的E要么是一个类,要么是一个接口,而类和接口第一个字母大写,所以这里习惯使用的是大写的第一个字母,这并不是硬性规定,只是一种比较好的习惯。
  • 使用形式,<K,V>

泛型在集合中的应用

  • 在使用的类或者接口中,带有泛型的需要明确泛型参数,虽然可以不使用泛型,但那是一个不好的习惯,而且主要也是为了兼容老版本。
List<String> listStr = new ArrayList<>();
        listStr.add("str1");
        listStr.add("str2");
        listStr.add("str3");
        Iterator<String> it = listStr.iterator();
        while (it.hasNext()) {
            System.out.println("item = " + it.next());
        }

泛型在类中的使用

  • 静态方法不能使用泛型,如果静态方法要使用泛型,则直接把泛型定义在方法上。
  • 当类中所使用的引用类型不确定的时候,使用泛型。
  • 在类中的应用eg
class Test<T> {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

泛型在方法中的应用

  • 将方法定义在方法上eg:
class GenericDemo4 {

    public static void main(String[] args) {
        Tool tool = new Tool();
        //方法中的泛型调用
        tool.print(new Integer(3));
        tool.print2(new Integer(4),new Float(3.0));
    }
}

class Tool {
    /**
     * 泛型在方法中的使用
     */
    public <P> void print(P p) {
        System.out.println("p = " + p);
    }

    /**
     * 泛型在方法中的使用2
     */
    public <K,V> void print2(K k,V v) {
        System.out.println("k = " + k + ",v=" + v);
    }
}
  • 在方法中调用泛型数据类型的方法
;

class GenericDemo5 {
    public static void main(String[] args) {
        Util<Student> util = new Util(new Person("deHua",32));
        util.printInfo();

        Util<Student> util2 = new Util(new Student("chaoWei",35,"001"));
        util2.printInfo();
    }
}

/**
 * 泛型中使用extends 关键字来确定基本类型,否则只可以调用Object中的方法
 */
class Util<T extends Person> {

    private T t;

    public Util(T t) {
        this.t = t;
    }

    public void printInfo() {
        System.out.println("t.name = " + t.getName());
        System.out.println("t.age = " + t.getAge());
    }

}

class Person {

    private String name;
    private int age;

    public Person(String name,int age) {
        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(int age) {
        this.age = age;
    }
}

class Student extends Person {
    public Student(String name,int age,String classNo) {
        super(name,age);
        this.classNo = classNo;
    }

    private String classNo;
}

泛型在接口中的应用

  • 泛型接口的定义
interface Test<T>{
	public void method(T t);
}
  • 实现的接口中依然不确定具体的类型
interface Info<T> {
    public void getInfo(T t);
}

/**
 * 接口的实现类还是不知道接口泛型的类型,则,在InfoChild中定义泛型,在接口中继续使用
 * 某些时候,定义了一样的明细,但是意义已经完全不同,InfoChild<P> 定义了Info<P>中的类型
 * 如果碰巧InfoChild<T>则在这里的Info<T> 的类型跟InfoChild<T>中的T一致
 */
class InfoChild<P> implements Info<P> {
    @Override
    public void getInfo(P t) {
        
    }
}

泛型的通配符:? 未知类型

对类型不确定,并且不对类型进行操作的时候使用

public static void printColl(Collection<?> col){
        Iterator<?> it =col.iterator();
        //这里没有类型只能使用Object接收
        //因为类型提升的关系,将拿不到Collection中的元素的具体方法和类型
        Object obj = it.next();
    }
  • 使用泛型定义
public static <T> void printColl2(Collection<T> col) {
        Iterator<T> it = col.iterator();
        T t = it.next();
    }

泛型范围

  • ? extend E :接受E类型或E类型的子类型,上限!
  • ? super E :接受E类型或者E类型的父类型,下限!

使用时
一般存元素的时候使用上限
取元素的时候一般使用下限