为什么用泛型
早期的Object类型可以接收任意的对象类型,但实际的使用中,会有类型转型的问题,也就存在隐患,所以java提供泛型来解决这个问题
什么是泛型
-
泛型也就是“参数化类型”,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式,然后在使用/调用时传入具体的类型
public class Parent<T> {
T color;}
如此 我们可以先定义一个父类泛型
/* 父类是泛型类 子类继承父类后,也是泛型类,子类定义类型后,父类类型也随之明确了 */
public class Child<T>extends Parent<T>{
T name;
public static void main(String[] args) {
Child<String> c = new Child<String>();
}}
/*
子类继承一个泛型类
如果子类 没有定义泛型,那么父类的类型必须在声明时就明确下来
*/
public class Child1 extends Parent<String>{
String name;
public static void main(String[] args) {
Child1 c = new Child1();
}
}
-
当子类继承了父类泛型的话,如果子类确定了类型,那么父类也就随之确定了
-
子类继承一个泛型类,如果子类没有定义泛型的话,那么父类在声明时就要明确下来自己的类型
泛型通配符
什么是类型通配符
-
类型通配符一般使用“?” 代替具体的类型实参
-
所以类型通配符是类型实参,而不是形参
public class Demo<T> {
public T name;}
我们这里先定义一个父类泛型
public class Test {
/*
? 类型通配符 任意的 表示实际参数类型
*/
/*void test(Demo<?> d){
}*/
/*
? extends Number 类型上限 传入的实参的泛型类型只能是Number 以及Number的子类
void test(Demo<? extends Number> d){
}*/
/*
? super Number 类型下限 传入的实参的泛型类型只能是Number 以及Number的父类
*/
void test(Demo<? super Number> d){
}
public static void main(String[] args) {
Test t = new Test();
Demo<Object> d1 = new Demo<>();
Demo<Number> d2 = new Demo<>();
Demo<String> d3 = new Demo<>();
t.test(d1);
t.test(d2);
//t.test(d3);
}
}
-
这里主要了解两点:
类型上限:
-
? extends Number 类型上限 传入的实参的泛型类型只能是Number 以及Number的子类
类型下限:
-
? super Number 类型下限 传入的实参的泛型类型只能是Number 以及Number的父类
-