泛型

参数化类型:ParameterizedType

集合泛型

  • 集合中泛型的应用:通过指定泛型的数据类型,限制集合存储的元素的数据类型

泛型的原理

  1. 泛型的绑定:
    在创建类对象时,指定了泛型的具体类型;在编译时,检查数据类型是否符合泛型的要求;如果不符合,编译报错
  2. 泛型的擦除
    当编译检查类型没问题时,编译完成后,泛型会被擦除

注意:泛型仅仅是在编译期进行类型的强制检查;但当真正运行时,泛型已经被擦除掉

自定义泛型

  1. 类上定义泛型
// 1. 定义一个泛型
class 类名<泛型名称> extends 父类{}

// 2. 可以定义多个泛型
class 类名<泛型1,泛型2,…> extends 父类{}
  • 泛型名称:符合标识符的命名规范均可,编译运行不会报错;但是一般会通过一个大写字母,代表一个泛型;T(type) E(element) K(key) V(value)
  • 如何使用该泛型?
  1. 可以指定属性的数据类型
  2. 可以作为方法的返回值数据类型
  3. 可以作为方法的参数列表中的数据类型

示例:

public class FXDemo1 {
    public static void main(String[] args) {
        Paper<String> p = new Paper<String>();
        p.setContent("hello world");
        System.out.println(p.getContent());
        
    }
}

class Paper<E>{
    private E content;

    public E getContent() {
        return content;
    }

    public void setContent(E content) {
        this.content = content;
    }
}
  1. 接口上定义泛型
// 1. 定义一个泛型
interface 接口名<泛型名称>{}

// 2. 可以定义多个泛型
interface 接口名<泛型1,泛型2,…>{}
  • 类似于类上定义泛型
  • 可以定义多个泛型
public class FXDemo2 {
    public static void main(String[] args) {
        // new InterImpl().method("123");
        new InterImpl<String>().method("123");
    }
}

interface Inter<T>{
    public void method(T num);
}

// 创建类时绑定泛型
//class InterImpl implements Inter<String>{
//    @Override
//    public void method(String value) {
//        System.out.println(value);
//    }
//}

// 创建对象时绑定泛型
class InterImpl<T> implements Inter<T>{
    @Override
    public void method(T value) {
        System.out.println(value);
    }
}
  1. 方法上定义泛型
public <T> T method(T t){
    return t;
}

示例:

public class FXDemo3 {
    public static void main(String[] args) {
        Demo d = new Demo();
        String s = d.method("abc");
        Demo1 d1 = d.method1("abc",100);
        System.out.println(s+","+d1.getT1()+","+d1.getT2());
    }
}

class Demo{
    private String str;

    public<T> T method (T t){
        // public<T>    T method (T t){
        //  泛型的定义 返回值类型   参数类型
        return t;
    }
    public <T1,T2> Demo1 method1 (T1 t1, T2 t2){
        Demo1<T1,T2> d1= new Demo1<T1,T2>();
        d1.setT1(t1);
        d1.setT2(t2);
        return d1;
    }
}

class Demo1<T1,T2>{
    private T1 t1;
    private T2 t2;

    public T1 getT1() {
        return t1;
    }

    public void setT1(T1 t1) {
        this.t1 = t1;
    }

    public T2 getT2() {
        return t2;
    }

    public void setT2(T2 t2) {
        this.t2 = t2;
    }
}

泛型的通配 (很少用)

  • 通过 ? 来表示泛型的类型暂时还不确定,直到具体类型传入时,会将 ? 和具体类型绑定;
public class FXDemo4 {
    public static void main(String[] args) {
        method(new Demo2<String>());
        method(new Demo2<Integer>());
    }

    public static void method(Demo2<?> d){
        // d.setField("abc");
        // error 无法将具体类型和?绑定
        
        System.out.println(d.getField());
        // 可以绑定任意传入的类型
    }
}

class Demo2<T>{
    private T field;

    public T getField() {
        return field;
    }

    public void setField(T field) {
        this.field = field;
    }
}

泛型的上限和下限

  • 泛型上限:? extends 类名 — 传递的要么是该类本身要么是该类的子类
  • 泛型下限:? super 类名 — 传递的要么是该类本身要么是该类的父类
public class FXDemo5 {
    public static void main(String[] args) {
        method(new Demo2<Number>());
        method(new Demo2<Integer>());
        method2(new Demo2<B>());
        method2(new Demo2<A>());
    }
    public static void method(Demo2<? extends Number> d){
        // d.setField(100);
        System.out.println(d.getField());
    }

    public static void method2 (Demo2<? super B> d){
        d.setField(new B());
        System.out.println(d.getField());
    }
}

class A {}
class B extends A{}