集合类
首先我们了解一下集合框架,我们看一下类和接口的总览:
我们可以看到,所有的接口和类,除了Map,都实现了Iterable接口,这个接口是迭代器接口,也就是说,实现了这个接口的所有的类都能迭代,就是利用foreach来遍历我们的集合。因为Map本身是没有实现Iterable接口的,所以Map不能通过foreach来遍历,但是如果Map想要遍历,我们进入Map里面去看看:
HashMap和TreeMap的区别之一:TreeMap是根据比较K来插入的,而HashMap是根据它自己的哈希函数得出来的哈希值来进行数据存储的。
我们可以看到,TreeMap中的put方法是具有比较器的功能的,也就是每次put都会比较,而HashMap中的put方法,我们没有看到比较器。
接下来,回到Collection接口,要使用Collection接口中的方法,因为它是个接口,不能直接new,所以我们用ArrayList类来实现这个接口
包装类
装包/装箱 & 拆包/拆箱
了解的拆包和装包,我们来看一道面试题:
泛型
- 类名后的代表占位符,表示当前类是一个泛型类
- 基本数据类型,不能作为泛型类型的参数,要封装类
- 类型后加入<数据类类型>,该类型只能处理规定的数据类型
- 编译的时候,自动进行类型的检查
- 取出数据的时候,不需要强制类型转换
- 泛型类型的数组,不能直接new或者实例化:
T[] t = new T[]; 是错误的,T[] array = new (T[])Object[]; 这样能通过编译
泛型是如何编译的
-
擦除机制
查看字节码文件,所有的T都被换成了Objiect -
提出问题:
1、那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?
2、类型擦除,一定是把T变成Object吗?
那么如果要创建一个泛型数组,只能用反射的方式来创建
class MyArray<T> {
public T[] array;
public MyArray() {}
public MyArray(Class<T> clazz, int capacity) {
array = (T[]) Array.newInstance(clazz, capacity);
}
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] = val;
}
public T[] getArray() {
return array;
}
}
public class test {
public static void main(String[] args) {
MyArray<Integer> myArray1 = new MyArray<>(Integer.class,10);
Integer[] integers = myArray1.getArray();
}
}
泛型的上界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束
- 语法
class 泛型类名称 <类型形参 extends 类型边界>
public class MyArray <E extends Number>{
}
//只接受Number的子类型作为E的类型参数(E 可以是Number或者Number的子类),这就叫做泛型上界
MyArray<Integer> m1; // 正确,因为Integer是Number的子类型
MYArray<String> m2; // 编译错误,因为String不是Number的子类型
- 示例:
public class MyArray<E extends Comparable<E>> {
}
写一个泛型类,找出数组中的最大值
class Array<T extends Comparable<T>>{
public T findMax(T[] array) {
T max = array[0];
for (int i = 1; i < array.length; i++) {
if(max.compareTo(array[i]) < 0) {
max = array[i];
}
}
return max;
}
}
public class test {
public static void main(String[] args) {
Array<Integer> array = new Array<>();
Integer[] a = new Integer[]{2,1,9,6};
System.out.println("max = " + array.findMax(a));
}
}
泛型方法
方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }
//<类型形参列表> 一般只有在静态方法中,写在static后面
泛型进阶请移步到鄙人的另一篇博客:
泛型和泛型的进阶