java范型

范型

使用场景

范型主要是用于限定传入或是传出参数的类型。
主要有以下几种使用方式:

    /**
     * 在普通方法上使用
     * @param t
     * @param <T>
     */
    private <T> void fun(T t) {

    }

    /**
     * 在静态方法上使用
     * @param t
     * @param <T>
     */
    private static <T> void funSta(T t) {

    }

    /**
     * 在类上使用
     * @param <T>
     */
    static class InnerClass<T> {
        T item;
    }

通配符

无限通配符

无限通配符表示的是未知类型,表示不关心或者不能确定实际操作的类型,一般配合容器类使用。

public void testV(List<?> list) {}

需要注意的是: 无限通配符只能读的能力,没有写的能力。

public void testV(List<?> list) {
      Object o = list.get(0);
    //编译器不允许该操作
   // list.add("jaljal");
}

extends

定义了上限,期只有读的能力。此方式表示参数化的类型可能是所指定的类型,或者是此类型的子类。

//t1要么是Test2,要么是Test2的子类
public void testC(Test1<? extends Test2> t1) {
    Test2 value = t1.getValue();
    System.out.println("testC中的:" + value.getT());
}

super

定义了下限,有读的能力以及部分写的能力,子类可以写入父类。此方式表示参数化的类型可能是指定的类型,或者是此类型的父类

    static class InnerClass<T> {

        public InnerClass(T item) {
            this.item = item;
        }

        T item;

        public T getItem() {
            return item;
        }
    }

    /**
     * 这里InnerClass中的类型,只能是Student,或是Student的父类Person
     *
     * @param clazz
     */
    public static void test(InnerClass<? super Student> clazz) {
        System.out.println(clazz.getItem());
    }

调用

        InnerClass<Student> studentInnerClass = new InnerClass<>(student);
        InnerClass<Person> personInnerClass = new InnerClass<>(person);
        test(personInnerClass);
        test(studentInnerClass);

通配符不能用作返回值

如果返回值依赖类型参数,不能使用通配符作为返回值。可以使用类型参数返回方式:

public <T> T testA(T t, Test1<T> test1) {
    System.out.println("这是传入的T:" + t);
    t = test1.t;
    System.out.println("这是赋值后的T:" + t);
    return t;
}

总结

  1. 要从泛型类取数据时,用extends;
  2. 要往泛型类写数据时,用super;
  3. 既要取又要写,就不用通配符(即extends与super都不用)。
  4. 泛型中只有通配符可以使用super关键字,类型参数不支持 这种写法

PECS

PESC = producer-extens , consumer -super.

如果参数化类型表示一个 T 生产者,就使用 <? extends T>; 如果它表示一个 T 消费者, 就使用 <? super T>

PESC 这个助记符突出了通配符类型的基本原则。(Get and Put Principle)

例子

有三个类,它们的关系如下:

    public static void superTest(List<? super Student> list) {
        Student student = new Student();
        list.add(student);//这里List可以存放Student和Student的子类
        list.add(new SmallStudent());
        Object object = list.get(0);
    }

    public static void extendTest(List<? extends Person> list) {
        Person person = new Person();
        //list不能再存放任何元素
//        list.add(person);//编译报错
        Person person1 = list.get(0);
    }

对于方法superTest,它的入参为List,这个List的范型必须是Student的父类,在方法体内部,可以对list进行写入操作和读取操作。
使用范型的extend,Person的子类(包括自己)都可以作为List的范型传入方法,而且在读取的时候,作为Person读出,但是由于List本身其实不知道自己存入的类型是具体哪个类型,所以这个list不能进行修改操作

posted @ 2020-11-12 16:36  刃牙  阅读(202)  评论(0编辑  收藏  举报