泛型

泛型

参考视频: BV1xJ411n77R

应用场景

  1. 同一方法可以:
    1. 产生不同类型的实例对象(返回对象引用)
    2. 书写不同类型的泛型方法
    3. 接收不同类型的传入参数(输入对象引用)
    4. 抽象(字面意义的)地继承
  2. 同一接口可以:
    1. 产生不同类型的方法实现

上面是我自己总结的,描述的范围肯定有问题,不要拿去当做参考

格式

为了代码简洁,统一使用无参构造

常用的泛型缩写

  • E - Element (在集合中使用,因为集合中存放的是元素)
  • T - Type(表示Java 类,包括基本的类和我们自定义的类)
  • K - Key(表示键,比如Map中的key)
  • V - Value(表示值)
  • N - Number(表示数值类型)
  • - (表示不确定的java类型)本文后面提到的通配
  • S、U、V - 2nd、3rd、4th types

案例

类:

public class GenericTest<T> {
    private T t;
    public T getT(){
        return t;
    }
}

类继承:

  • 非泛型类(必须要指明继承的父类的明确类型)
class GenericChild extends GenericTest<String> {
}
  • 泛型类(声明时泛型名与父类一样就行)
    • 当然子类也可以拓展泛型列表
class GenericAnotherChild<E, K> extends GenericTest<E>{
    private K k;

    public K getK() {
        return k;
    }

    public void setK(K k) {
        this.k = k;
    }
}

接口

public interface GenericInterface<T> {
    T printSomething();
}

类实现泛型接口:

  • 泛型类实现泛型接口
    • 泛型类也可以扩充泛型列表,这里为了保持间接不做赘述
    • 必须保证泛型类包括接口的泛型
public class GenericTest<T> implements GenericInterface<T>{
    private T t;

    @Override
    public T printSomething() {
        return (t);
    }

    public T getT() {
        return t;
    }

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

实例化

GenericTest<Integer> stringGenericTest = new GenericTest<>()

左右两侧类名后紧跟<> 并且右侧的不需要写

测试案例

上述代码的分别实例化:

public class Application {
    public static void main(String[] args) {
        // 继承泛型接口的泛型类
        GenericTest<Integer> stringGenericTest = new GenericTest<>();
        stringGenericTest.setT(1);
        Integer s = stringGenericTest.printSomething();
        System.out.println(s + "\t"+ s.getClass().getSimpleName());
        System.out.println("--------------------");

        // 继承泛型类的子类
        GenericChild genericChild = new GenericChild();
        genericChild.setT("Child");
        String s1 = genericChild.printSomething();
        System.out.println(s1 + "\t" + s1.getClass().getSimpleName());
        System.out.println("--------------------");

        // 继承泛型类的泛型子类
        GenericAnotherChild<String, Integer> stringIntegerGenericAnotherChild = new GenericAnotherChild<>();
        stringIntegerGenericAnotherChild.setK(10);
        stringIntegerGenericAnotherChild.setT("Number");
        String t = stringIntegerGenericAnotherChild.getT();
        Integer k = stringIntegerGenericAnotherChild.getK();
        System.out.println("t=" + t + "\t" + "K=" + k);
    }
}

STDOUT

1	Integer
--------------------
Child	String
--------------------
t=Number	K=10

类型通配符

是什么

用?问号代替具体的类型实参

能够代表任一类型

(目前来看用于创建方法时,面对泛型对象时出现的无法重载方法的问题)

案例

第一种使用类型通配符,第二种不使用通配符

  • 使用类型通配符
    • 此时IDEA不会标黄,推测是正式的写法
    • 注意此时接收或者处理传递的对象 genericTest时,应该按照Object来处理
    public static void showData2nd(GenericTest<?> genericTest) {
        Object data = genericTest.getT();
        System.out.println(data);
    }
  • 不适用通配符
    • 和上面一样,IDEA没有报错但是传递类型 GenericTest标黄
    • 提示 Raw use of parameterized class 'GenericTest'
    • 推测是不规范的写法,但是也依旧可以用
    public static void showData(GenericTest generictest){
        Object data = generictest.getT();
        System.out.println(data);
    }

类型通配符的上下限

这里为便于理解通配符,所以建立一个不含泛型的继承树

为了方便查阅,这里只列出继承关系和类内实例变量,构造器和get/set/toString方法均取IDEA默认。

/** 类继承树
 * Object
 *   - Animal {private String species;}
 *       - Cat {private String speciesOfCat;}
 *           - MiniCat {private String name; private int age;}
 */

Animal.java

public class Animal {
    private String species;

    public Animal() {
    }

    public Animal(String species) {
        this.species = species;
    }

    public String getSpecies() {
        return species;
    }

    public void setSpecies(String species) {
        this.species = species;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "species='" + species + '\'' +
                '}';
    }
}

Cat.java

public class Cat extends Animal{
    private String speciesOfCat;

    public Cat() {
    }

    public Cat(String speciesOfCat) {
        this.speciesOfCat = speciesOfCat;
    }

    public String getSpeciesOfCat() {
        return speciesOfCat;
    }

    public void setSpeciesOfCat(String speciesOfCat) {
        this.speciesOfCat = speciesOfCat;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "speciesOfCat='" + speciesOfCat + '\'' +
                '}';
    }
}

MiniCat.java

public class MiniCat extends Cat{
    private String name;
    private int age;

    public MiniCat() {
    }

    public MiniCat(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;
    }

    @Override
    public String toString() {
        return "MiniCat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

创建对象

        ArrayList<Animal> animals = new ArrayList<>();
        ArrayList<Cat> cats = new ArrayList<>();
        ArrayList<MiniCat> miniCats = new ArrayList<>();

        // 填充 animals
        animals.add(new Animal("猫"));
        animals.add(new Animal("狗"));
        animals.add(new Animal("鼠"));
        // 填充 cats
        cats.add(new Cat("暹罗"));
        cats.add(new Cat("中华田园猫"));
        cats.add(new Cat("金渐层"));
        // 填充 miniCats、
        miniCats.add(new MiniCat("汤姆",2));
        miniCats.add(new MiniCat("老汤姆",7));
        miniCats.add(new MiniCat("汤姆妈",4));

上限之于方法

类/接口<? extends 实参类型>

限定泛型的类型只能是传入的 实参类型 本身或者是其子类型

也就是截断了继承树,只保留其及之下的继承树

可见其遍历时的枚举对象类型是传入的上限 Cat

    public static void showAnimalExtends(ArrayList<? extends Cat> arrayList) {
        for (Cat cat : arrayList) {
            System.out.println(cat.toString());
        }
    }

上限测试方法

        // extends
        showAnimalExtends(animals);// 编译报错
        showAnimalExtends(cats);
        showAnimalExtends(miniCats);

下限之于方法

类/接口<? super 实参类型>

截断了继承树,只保留其及之上的继承树

可见其遍历时的枚举对象类型是Object, 毕竟每一个类都继承自Object

    public static void showAnimalSuper(ArrayList<? super Cat> arrayList) {
        for (Object o : arrayList) {
            System.out.println(o);
        }

下限测试方法

        // super
        showAnimalSuper(animals);
        showAnimalSuper(cats);
        showAnimalSuper(miniCats);// 编译报错

完整测试用例

(去掉编译错误行后)

    public static void main(String[] args) {
        ArrayList<Animal> animals = new ArrayList<>();
        ArrayList<Cat> cats = new ArrayList<>();
        ArrayList<MiniCat> miniCats = new ArrayList<>();

        // 填充 animals
        animals.add(new Animal("猫"));
        animals.add(new Animal("狗"));
        animals.add(new Animal("鼠"));
        // 填充 cats
        cats.add(new Cat("暹罗"));
        cats.add(new Cat("中华田园猫"));
        cats.add(new Cat("金渐层"));
        // 填充 miniCats、
        miniCats.add(new MiniCat("汤姆",2));
        miniCats.add(new MiniCat("老汤姆",7));
        miniCats.add(new MiniCat("汤姆妈",4));

        // extends
//        showAnimalExtends(animals);
        showAnimalExtends(cats);
        showAnimalExtends(miniCats);

        // super
        showAnimalSuper(animals);
        showAnimalSuper(cats);
//        showAnimalSuper(miniCats);

    }

STDOUT:

	extends
showAnimalExtends(cats)
Cat{speciesOfCat='暹罗'}
Cat{speciesOfCat='中华田园猫'}
Cat{speciesOfCat='金渐层'}

showAnimalExtends(miniCats)
MiniCat{name='汤姆', age=2}
MiniCat{name='老汤姆', age=7}
MiniCat{name='汤姆妈', age=4}

	super
showAnimalSuper(animals)
Animal{species='猫'}
Animal{species='狗'}
Animal{species='鼠'}

showAnimalSuper(cats)
Cat{speciesOfCat='暹罗'}
Cat{speciesOfCat='中华田园猫'}
Cat{speciesOfCat='金渐层'}

Process finished with exit code 0

泛型通配上下限案例

继承树

/**
 * Object
 *   - Animal<T> {private T theAnimal;}
 *       - Cat<T> extends Animal<T> {private T theCat;
 *           - MiniCat<T> extends Cat<T> {private T theMiniCat;}
 */

使用时先把类当成非泛型类,有了整体结构之后将泛型再放进去

Animal.java

package pair.generic;

public class Animal<T> {
    private T theAnimal;

    public Animal() {
    }

    public Animal(T theAnimal) {
        this.theAnimal = theAnimal;
    }

    public T getTheAnimal() {
        return theAnimal;
    }

    public void setTheAnimal(T theAnimal) {
        this.theAnimal = theAnimal;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "theAnimal=" + theAnimal +
                '}';
    }
}

Cat.java

package pair.generic;

public class Cat<T> extends Animal<T>{
    private T theCat;

    public Cat() {
    }

    public Cat(T theCat) {
        this.theCat = theCat;
    }

    public T getTheCat() {
        return theCat;
    }

    public void setTheCat(T theCat) {
        this.theCat = theCat;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "theCat=" + theCat +
                '}';
    }
}

MiniCat.java

package pair.generic;

public class MiniCat<T> extends Cat<T>{
    private T theMiniCat;

    public MiniCat() {
    }

    public MiniCat(T theMiniCat) {
        this.theMiniCat = theMiniCat;
    }

    public T getTheMiniCat() {
        return theMiniCat;
    }

    public void setTheMiniCat(T theMiniCat) {
        this.theMiniCat = theMiniCat;
    }

    @Override
    public String toString() {
        return "MiniCat{" +
                "theMiniCat=" + theMiniCat +
                '}';
    }
}

上限测试方法

    public static void showItExtends(ArrayList<? extends Cat<?>> arrayList) {
        for (Cat<?> cat : arrayList) {
            System.out.println(cat);
        }
    }

        // extends
        showItExtends(animals);// 编译错误
        showItExtends(cats);
        showItExtends(miniCats);

下限测试方法

    public static void showItSuper(ArrayList<? super Cat<?>> arrayList) {
        for (Object o : arrayList) {
            System.out.println(o);
        }
    }

        // super
        showItSuper(animals);
        showItSuper(cats);
        showItSuper(miniCats);// 编译错误

测试用例

    public static void main(String[] args) {
        ArrayList<Animal<?>> animals = new ArrayList<>();
        ArrayList<Cat<?>> cats = new ArrayList<>();
        ArrayList<MiniCat<?>> miniCats = new ArrayList<>();

        // animals
        animals.add(new Animal<>("猫"));
        animals.add(new Animal<>("狗"));
        animals.add(new Animal<>("鼠"));
        // cats
        cats.add(new Cat<>("暹罗"));
        cats.add(new Cat<>("中华田园猫"));
        cats.add(new Cat<>("金渐层"));
        // miniCats
        miniCats.add(new MiniCat<>("汤姆"));
        miniCats.add(new MiniCat<>("老汤姆"));
        miniCats.add(new MiniCat<>("汤姆妈"));

        // extends
        System.out.println("\n\textends");
//        showItExtends(animals);// 编译错误
        System.out.println("showItExtends(cats)");
        showItExtends(cats);
        System.out.println("showItExtends(miniCats)");
        showItExtends(miniCats);

        // super
        System.out.println("\n\tsuper");
        System.out.println("showItSuper(animals)");
        showItSuper(animals);
        System.out.println("showItSuper(cats)");
        showItSuper(cats);
//        showItSuper(miniCats);// 编译错误

    }

STDOUT


	extends
showItExtends(cats)
Cat{theCat=暹罗}
Cat{theCat=中华田园猫}
Cat{theCat=金渐层}
showItExtends(miniCats)
MiniCat{theMiniCat=汤姆}
MiniCat{theMiniCat=老汤姆}
MiniCat{theMiniCat=汤姆妈}

	super
showItSuper(animals)
Animal{theAnimal=猫}
Animal{theAnimal=狗}
Animal{theAnimal=鼠}
showItSuper(cats)
Cat{theCat=暹罗}
Cat{theCat=中华田园猫}
Cat{theCat=金渐层}

Process finished with exit code 0

*暂时写到这了,学到更多的继续往后补充 2021年12月19日

posted @ 2021-12-19 11:36  jentreywang  阅读(38)  评论(0编辑  收藏  举报