泛型的初识
引入:
创建了一个瓶子,什么东西都装
后来外面加一层包装,只装草莓味的,西瓜味的等等
包装——泛型:让类型更加明确
jdk1.5后 设计了泛型的概念 泛型即“类型参数”,想到 实参和形参
public interface Compareble<T> {}
class Person implements Comparable<Person> {//传了什么类型就是什么类型
public static void main(String[] args) {
}
}
泛型的好处
节省代码——在创建比较器的时候,不用实现强转
可以让代码的可读性更强
泛型的相关名词
T:type 类型
E:Element 元素
K:key
V:value
Map<K, V>
不同字母代表 为了见名知意 都是代表 类型未知
泛型可以写在哪里
类上 泛型类 ArrayList<Integer>
LinkedList
接口上 泛型接口 public interface List<E>
方法上 泛型方法 当方法执行的时候才知道上什么类型
public static <T> boolean addAll(Collections<? super T> c, T... elements) {}
注意:泛型方法<T> 在返回类型(boolean)前面
泛型类的使用
不同老师 给出分数的数据类型不同
public class Main {
public static void main(String[] args) {
Student<String> s1 = new Student<>("王安石", "非常棒");
Student<Double> s2 = new Student<>("李白", 100.1);
Student<Character> s3 = new Student<>("王维", 'A');
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
}
class Student<T> {//类型化参数
String name;
T score;
public Student() {
}
public Student(String name, T score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
输出:
Student{name=‘王安石’, score=非常棒}
Student{name=‘李白’, score=100.1}
Student{name=‘王维’, score=A}
注意:此处的100.1不能写成100 因为是Double类型,无法进行自动装箱
泛型的上限
如何判断一个元素 是数 还是 不是数?
Integer Double BigDecimal 都继承了Number 都实现了Comparale
T:既是Number 的孩子 也是 Comparable<T> 的孩子
指定了 T 的上限:类型范围 不能超过父亲
class SumTools<T extends Number & Comparable<T>>
实现泛型的加法
泛型的擦除
擦除一:
- 当一个泛型类 或者 泛型接口 没有指定上限 并且没有传入泛型
- 没有指定泛型
那么默认泛型为Object类型,若有上限既是上限
擦除二:
- 局部变量的泛型在于编译后会消失
方法形参、成员变量则会保留
泛型方法
注意指定泛型的上限,实现了Comparable的类型才能使用该方法进行排序
代表任意类型
类型的通配符:
E
T
K
V
?:代表任意类型
? extends T:传入类型(?)是当前类型(?)也可以是当前类型(T)的孩子
? super T:传入类型 可以是当前类型(?)也可以是当前类型(T)的父类——泛型的下限
public void test01(Student<Object> kk) {
}
public void test02(Student<?> kk) {
}
泛型的注意
泛型的限制
?:当使用?作为泛型的时候 只能传入null值
可以理解为,我长大后充满希望,可以成为科学家,医生,老师等等,但是我不是任何一个,唯有null
无法确定孩子是哪一个 只有null是确定的
?都是number的孩子 以及number
?都是number的父亲以及number
使用了多态,可以放入?的子类