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;
}
总结
- 要从泛型类取数据时,用extends;
- 要往泛型类写数据时,用super;
- 既要取又要写,就不用通配符(即extends与super都不用)。
- 泛型中只有通配符可以使用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不能进行修改操作