文章目录
1.泛型的基础知识
泛型适用于许多类型,可以传类型
1.1主要目的
指定当前容器,要持有什么类型的对象,让编译器去做检查
1.2语法
class 泛型类名称<类型形参列表> {
}
举例:
class MyArray<T> {
public T[] array = (T[])new Object[10];
public void setVal(int pos,T val){
array[pos] = val;
}
public T getPos(int pos){
return array[pos];
}
}
public class TestDame {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();
myArray.setVal(0,10);
myArray.setVal(1,13);
int ret = myArray.getPos(1);
MyArray<String> myArray1 = new MyArray<>();
System.out.println(ret);
myArray1.setVal(2,"hello");
}
}
1.3 < T >
只是一个占位符,代表当前类是一个泛型类
1.4意义
可以自动进行类型检查;可以自动进行类型转换
1.5注意
不能new泛型类型的数组;尖括号当中的类型,不参与组成;尖括号当中的数据不能是简单类型,只能是包装类类型
1.6泛型到底是怎样编译的?
擦除机制:编译的时候会将T擦除为object
1.7为什么不能实例化泛型类型数组
数组在运行时存储和检查类型信息,然而,泛型在编译时检查类型错误,返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,运行的时候,直接转给Integer类型的数组,编译器认为是不安全的
1.8泛型的上界(无下界)
语法:
T extends Number
T 是Number或者Number的子类
特殊:
T extends Comparable< T >
T 是实现了Comparable接口的子类
1.9泛型方法
语法:
方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表){…}
public static <E> void swap(E[] array, int i, int j) {
E t = array[i];
array[i] = array[j];
array[j] = t;
}
1.10泛型的父子类关系
public class MyArrayList<E> { ... }
// MyArrayList<Object> 不是 MyArrayList<Number> 的父类型
// MyArrayList<Number> 也不是 MyArrayList<Integer> 的父类型
2.通配符
通配符是用来解决泛型无法协变的问题(协变指的是本身是父子类关系,而在泛型中却不是父子类关系)
2.1通配符的上界
不适合写入;适合读取
语法:
<? extends Number>
可以传入的参数类型是Number或者Number的子类
public static void main(String[] args) {
ArrayList<Integer> arrayList1 = new ArrayList<>();
ArrayList<String> arrayList2 = new ArrayList<>();
List<? extends Number> list = arrayList1;
//List<? extends Number> list1 = arrayList2;//Number不是String的父类
//list.add(1,2);//不适合写入
Number number = list.get(0);//适合读取
}
// 需要使用通配符来确定父子类型
MyArrayList<? extends Number> 是 MyArrayList <Integer>或者 MyArrayList<Double>的父类类型
MyArrayList<?> 是 MyArrayList<? extends Number> 的父类型
2.1通配符的下界
适合写入,不适合读取
语法:
<? super Integer>
可以传入Integer或者Integer的父类
public static void main(String[] args) {
ArrayList<? super Person> list = new ArrayList<Person>();
//ArrayList<? super Person> list1 = new ArrayList<Student>();//传入的必须是Person或者Person的父类
//最小的粒度Person,添加的是person或者Person的子类
list.add(new Student());
list.add(new Person());//适合写入
//Person person = list.get(0);不适合读取
Object student = list.get(0);//正确的读取方式
}
MyArrayList<? super Integer> 是 MyArrayList<Integer>的父类类型
MyArrayList<?> 是 MyArrayList<? super Integer>的父类类型
3.包装类
除了 Integer (int) 和 Character (char), 其余基本类型的包装类都是首字母大写。
3.1装箱和插箱
装箱:从基本数据类型到包装类类型
拆箱:从包装类类型到基本数据类型
public static void main(String[] args) {
Integer a = 10;//显示的装箱
int i = a;//隐式的拆箱
int i1 = a.intValue();//显示的拆箱
double i2 = a.doubleValue();
short i3 = a.shortValue();
}
3.2面试题(包装类的应用)
public static void main(String[] args) {
Integer a = 100;
Integer b = 100;
Integer c = 200;
Integer d = 200;
System.out.println(a == b);//true
System.out.println(c == d);//false
}
在显示装箱的时候,会自动调用Integer.valueOf() ,而valueOf的底层的范围是 [ - 128 , 127 ],当c=d=200的时候,if进不去,c和d分别new了一个新的对象,所以不相等