引言
Java 集合框架,又被称为容器,是定义在 java.util 包下的一组接口和它的实现类。
其主要作用是可以将多个元素置于一个单元中,用于对这些元素进行即平时我们增删查改。
一、类和接口总览
其中 Iterable 是一个接口,表示实现该接口的类是可以逐个元素进行遍历的。
Collection 也是一个接口,该接口中规范了后序集合框架中常用的一些方法
至于后续的一些接口和实现类,小伙伴可以自己去 IDEA 编译器中查看。后面会提到怎么操作来查看这些方法。
二、集合框架的重要性
- 使用成熟的集合框架,有助于我们便捷、快速的写出高效、稳定的代码
- 学习背后的数据结构知识,有助于我们理解各个集合的优缺点及使用场景
三、集合框架后的集合类
-
Collection:一个接口,包含了大部分集合框架中常用的一些方法。
-
List:是一个接口,规范了ArrayList 和 LinkedList中要实现的方法。
ArrayList:实现了List接口,底层为动态类型顺序表
LinkedList:实现了List接口,底层为双向链表 -
Stack:底层是栈,栈是一种特殊的顺序表。
-
Queue:底层是队列,队列是一种特殊的顺序表。
-
Deque:双端队列。
-
Set:集合,是一个接口,里面放置的是 K 模型。
HashSet:底层为哈希桶,查询的时间复杂度为O(1)
TreeSet:底层为红黑树,查询的时间复杂度为O( log2N ), key 是有序的 -
Map:映射,里面存储的是 K-V 模型的键值对。
HashMap:底层为哈希桶,查询时间复杂度为O(1)
TreeMap:底层为红黑树,查询的时间复杂度为O( log2N ), key 是有序的
四、Collection 接口
在 IDEA 编译器中,我们点击左下角 Structure,或者使用快捷键 [ Alt + 7 ],即可找到对应的接口或类的方法。
程序清单1:
public class Test1 {
public static void main(String[] args) {
Collection<String> collection= new ArrayList<String>();
collection.add("hello");
collection.add("world");
System.out.println(collection);
collection.clear();
System.out.println(collection);
System.out.println(collection.isEmpty());
}
}
输出结果:
程序清单2:
public class Test2 {
public static void main(String[] args) {
Collection<String> collection= new ArrayList<String>();
collection.add("hello");
collection.add("world");
System.out.println(collection);
System.out.println("---------------");
Object[] objects = collection.toArray();
System.out.println(Arrays.toString(objects));
}
}
输出结果:
五、包装类
程序清单3:
public class Test3 {
public static void main(String[] args) {
String str = "123";
int ret = Integer.valueOf(str);
System.out.println(ret + 1);
}
}
输出结果:
装箱操作
新建一个 Integer 类型对象,将输入参数的值放入对象的某个属性当中。
拆箱操作
将 Integer 对象中的值取出,放到一个基本数据类型中。
例子1
程序清单4:
public class Test4 {
public static void main(String[] args) {
Integer a1 = 123; //隐式装箱
int b1 = a1; //隐式拆箱
System.out.println(a1 + b1);
System.out.println("------------");
Integer a2 = Integer.valueOf(123);
Integer a3 = new Integer(123);
//上面两行代码都是显示装箱操作
int b2 = a2.intValue();
Double c2 = a2.doubleValue();
//上面两行代码都是显示拆箱操作
System.out.println(a2);
System.out.println(a3);
System.out.println(b2);
}
}
输出结果:
例子2
程序清单5:
public class Test5 {
public static void main(String[] args) {
Integer a1 = 123;
Integer b1 = 123;
System.out.println(a1 == b1);
Integer a2 = 129;
Integer b2 = 129;
System.out.println(a2 == b2);
}
}
输出结果:
在源代码中,我们发现 cache 数组返回值是有范围限制的,而这个范围限制和 i 有很大关联,当我们取得的值在数组范围内,我们就存储,当不在数组范围内,我们就返回并创建一个新的对象。那么我们现在对这个 cache 数组进行分析。
由上面的图可以发现,边界 low = -128,high = 127
那么对应的区间即为 [ -128, 127 ],我们将两边区间代入数组,就像高等数学中,我们知道定义域,往函数式一带,就能求出值域。
//数组 cache
cache[i + (-IntegerCache.low)
当 i = -128,cache[ 0 ]
当 i = 127,cache[ 255 ]
那么我们模拟数组内部的结果就如下图所示:数组的长度为256,cache[ 0 ] = -128,cache[ 255 ] = 127.
经过上面的分析之后,我们再回过头看程序清单中对应的代码:
Integer a2 = 129;
Integer b2 = 129;
System.out.println(a2 == b2);
129 > 127,很明显,这已经不在数组范围之内了,那么系统就会产生新的对象,这样导致的结果就是两者拿到的地址不同,所以输出 false.