数组与容器(*)
Java 中常用的存储容器就是数组和容器,二者有以下区别:
-
存储大小是否固定
- 数组的长度固定;
- 容器的长度可变。
-
数据类型
- 数组可以存储基本数据类型,也可以存储引用数据类型;
- 容器只能存储引用数据类型,基本数据类型的变量要转换成对应的包装类才能放入容器类中。
排序 (*)
「Arrays中的sort()方法主要是针对各种数据类型(基本数据类型和引用对象类型)的数组元素排序。」
「Collections中的静态方法的Collection.sort()主要是针对集合框架中的动态数组,链表,树,哈希表等( ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap )进行排序。」
但是并不是所有的对象可以进行排序的,要先实现排序还需要定义比较器,也就是定义比较规则 。java提供了两个方法来定义比较规则:
- 「对象实现Comparable 接口」
- 「定义比较器实现Comparator接口」
Cloneable
Java 中 一个类要实现 clone 功能 必须实现 Cloneable 接口,否则在调用 clone() 时会报 CloneNotSupportedException 异常。
Java 中所有类都默认继承 java.lang.Object 类,在 java.lang.Object 类中有一个方法 clone(),这个方法将返回 Object 对象的一个拷贝。Object 类里的 clone() 方法仅仅用于浅拷贝(拷贝基本成员属性,对于引用类型仅返回指向改地址的引用)。
如果 Java 类需要深拷贝,需要覆写 clone() 方法。
fail-fast
fail-fast 是 Java 容器的一种错误检测机制。当多个线程对容器进行结构上的改变的操作时,就可能触发 fail-fast 机制。
容器在迭代操作中改变元素个数(添加、删除元素)都可能会导致 fail-fast。抛出 ConcurrentModificationException 异常
fail-fast 两种解决方案:
- 在遍历过程中所有涉及到改变容器个数的地方全部加上
synchronized或者直接使用Collections.synchronizedXXX容器,这样就可以解决。但是不推荐,因为增删造成的同步锁可能会阻塞遍历操作,影响吞吐。 - 使用并发容器,如:
CopyOnWriterArrayList。
Java 容器之 List
ArrayList 和 LinkedList
-
ArrayList基于动态数组实现,存在容量限制,当元素数超过最大容量时,会自动扩容;LinkedList基于双向链表实现,不存在容量限制。 -
ArrayList随机访问速度较快,随机插入、删除速度较慢;LinkedList随机插入、删除速度较快,随机访问速度较慢。 -
ArrayList和LinkedList都不是线程安全的。
Vector 和 Stack
Vector 和 Stack 的设计目标是作为线程安全的 List 实现,替代 ArrayList。
Vector-Vector和ArrayList类似,也实现了List接口。但是,Vector中的主要方法都是synchronized方法,即通过互斥同步方式保证操作的线程安全。Stack-Stack也是一个同步容器,它的方法也用synchronized进行了同步,它实际上是继承于Vector类。
ArrayList 默认初始容量大小为 10 ,添加元素时,如果发现容量已满,会自动扩容为原始大小的 1.5 倍。因此,应该尽量在初始化 ArrayList 时,为其指定合适的初始化容量大小,减少扩容操作产生的性能开销。
ArrayList实现了Cloneable接口,默认为浅拷贝。ArrayList实现了Serializable接口,支持序列化,能通过序列化方式传输。