泛型:就是指在类定义时不会设置类中的属性或方法参数的具体类型,而是在类使用时(创建对象)再进行类型的定义。会在编译期检查类型是否错误。
类声明后的<>中这个T被称为类型参数,用于指代任意类型,实际上这个T只是个代表,写什么都可以。表示此时的value1,value2都是在类定义时没有明确类型,只有在使用时才告知编译器类型。出于规范,类型参数用单个的大写字母来代替
T:代表任意类
E:表示Element的意思,或是异常
@Data
class people<A, B> {
A value1;
B value2;
}
@Test
void test1() {
people<String,Long> people = new people();
people.setValue1("sb");
people.setValue2(1L);
log.info(people.toString());//people(value1=sb, value2=1)
}
表示此方法是个泛型方法,有一个类型参数,不是返回值,只是告知编译器这是一个泛型的声明
@Data
@Slf4j
class people<A, B> {
A value1;
B value2;
//此处的泛型方法指的是有自己的类型参数,这里的A和类上的A不是同一个
public <A> void test(A t) {
log.info(String.valueOf(t));
}
}
@Test
void test2() {
people<String, Long> people = new people();
people.setValue1("sb");
people.setValue2(1L);
log.info(people.toString());//people(value1=sb, value2=1)
people.test(100L);
}
子类在实现接口时有两种选择,①要么继续保留泛型,②要么定义子类时明确类型
interface INew<T>{
T getName(T t);
}
class INewImpl1<T> implements INew<T>{
@Override
public T getName(T o) {
return o;
}
}
class INewImpl2 implements INew<String>{
@Override
public String getName(String o) {
return o;
}
}
@Data
@Slf4j
class Message<T, K> {
T value1;
K Value2;
public void fun(Message<?, ?> sb) {
log.info("value1===={}", sb.getValue1());
log.info("value1===={}", sb.getValue2());
}
}
@Test
void test3() {
Message message = new Message();
message.setValue1("aaa");
message.setValue2(222);
message.fun(message);
Message message2 = new Message();
message2.setValue1(111);
message2.setValue2("bbb");
message2.fun(message);
}
extends 类> 表示?可以指代任何类型,但是该类型必须是后面类的子类。
可以是类本身,或者子类,除此之外其他类型都不可以。
@Data
@Slf4j
class Message2<T, K> {
T value1;
K Value2;
public void fun(Message2<? extends String, ? extends Integer> sb) {
log.info("value1===={}", sb.getValue1());
log.info("value1===={}", sb.getValue2());
}
}
@Test
void test4() {
Message2<String, Integer> message = new Message2<>();
message.setValue1("aaa");
message.setValue2(222);
message.fun(message);
Message2<Object, Object> message2 = new Message2();
message2.setValue1(111);
message2.setValue2("bbb");
message2.fun(message2);
}
super 类> 此时?表示可以指代任意类型,但是该类型必须是后面类的父类。
此时表示?必须是String及其父类,所有此时?只能指代String或Object。
注意:下限通配符可以调用对象的setter方法设置一个具体的属性值,无论?是什么类型,规定好的下限类型一定可以通过向上转型变为父类。
@Data
@Slf4j
class Message3<T, K> {
T value1;
K Value2;
public void fun(Message3<? super String, ? super Integer> sb) {
log.info("value1===={}", sb.getValue1());
log.info("value1===={}", sb.getValue2());
}
}
@Test
void test5() {
Message3<String, Integer> message = new Message3<>();
message.setValue1("aaa");
message.setValue2(222);
message.fun(message);
Message3<Object, Object> message2 = new Message3<>();
message2.setValue1(111);
message2.setValue2("bbb");
message2.fun(message2);
Message3<Integer, String> message3 = new Message3<>();
message3.setValue1(111);
message3.setValue2("bbb");
message3.fun(message3);
}
类型擦除:所有泛型类型参数,若没有设置泛型上限,则编译之后统一擦除为Object类型,若设置了泛型上限,则编译之后统一擦除为相应的泛型上限。