引言
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.