在介绍常见集合类之前先给大家看看这个UML图(就如同设计师需要看懂设计稿一样)
注意:List、Set、Map没有实现同一个接口 Map是一个单独的接口。它是键值对类型先有键(主键)再有值的
什么是UML?
UML是统一建模语言,是一种可视化的面向对象建模语言,是一种用来对真实世界物理进行建模的标准标记,用图形方式表现典型的面向对象系统的整个结构。它的作用域不局限于支持面向对象的分析与设计,还支持从需求分析开始的软件开发的全过程。
为了更好的看懂类图,大家可以点进下方链接了解了解UML类图几种关系的总结
UML类图几种关系的总结http://www.uml.org.cn/oobject/201609062.asp
List集合
特点:元素有序,且可重复
遍历:下标,foreach,迭代器
- List<Integer> list=new ArrayList<Integer>();
-
- @Before
- public void setup() {
- list.add(1);
- list.add(2);
- list.add(3);
- list.add(3);
- list.add(4);
- }
-
- /**
- * foreach遍历
- */
- @Test
- public void list01() {
- for(Integer e:list){
- System.out.println(e);
- }
- }
- /**
- * for循环
- */
- @Test
- public void list02() {
- for(int i=0;i<list.size();i++){
- System.out.println(list.get(i));
- }
- }
- /**
- * 迭代器
- */
- @Test
- public void list03() {
- Iterator<Integer> it = list.iterator();
- while(it.hasNext()) {
- System.out.println(it.next());
- }
- }
扩容:
代码示例:
- public void listKR()throws Exception {
- List<Integer> list=new ArrayList<Integer>();
- for(int i=0;i<=100;i++) {
- list.add(i);
- System.out.println("i :"+i);
- System.out.println("length :"+getListElsSize(list));
- }
- }
-
- private int getListElsSize(List obj)throws Exception {
- Class<? extends List> clazz = obj.getClass();
- Field f = clazz.getDeclaredField("elementData");
- f.setAccessible(true);
- Object[] object =(Object[]) f.get(obj);
- return object.length;
- }
效果如下:
实现
🟡ArrayList:是一个简单数据结构,具有超出容量自动扩容,动态数组的特点。内部实现是基于基础的对象数组的。随机访问快但是不适合随机增加或删除。线程不安全
🟡LinkedList:LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)。适合做随机的增加或删除。以双向链表实现,链表无容量限制,允许元素为null,线程不安全。
🟡Vector:是线程安全的,但是并行性能慢,不建议使用
🟡CopyOnWriteArrayList:写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array,适合于读多,写少的场景。比Vector性能高,最终一致性。实现了List接口,使用方式与ArrayList类似。线程安全
题目要求:删除集合中所有为3的元素
数据准备:为方便演示,需要有紧挨在一起的两个或多个相同的元素
- List<Integer> list=new ArrayList<Integer>();
- list.add(1);
- list.add(2);
- list.add(3);
- list.add(3);
- list.add(4);
1️⃣第一种:for循环遍历list删除指定元素❎
- public void remove01() {
- for(int i=0;i<list.size();i++){
- if(list.get(i)==3)
- list.remove(i);
- }
- System.out.println(list);
- }
效果图如下:
很显然只删除了一个3,这是为什么呢?因为当删除到元素3的时候下面元素的位置会往上移那么原先第二个3的位置就成4了 所以没有删除成功
图形解读:
2️⃣第二种:for循环遍历list删除时将i--✅
- public void remove02() {
- for(int i=0;i<list.size();i++){
- if(list.get(i)==3)
- list.remove(i--);
- }
- System.out.println(list);
- }
效果图如下:
当删除第一个3时,3后面元素都会向上移动,而当前index等于2,后一个3会移除到index=2的位置,又因为index-1被跳回去了 所以删除成功!!!
3️⃣第三种:倒序遍历list是✅
- public void remove03() {
- for(int i=list.size()-1;i>=0;i--){
- if(list.get(i)==3){
- list.remove(i);
- }
- }
- System.out.println(list);
- }
效果图如下:
4️⃣第四种:forEach遍历list删除 ❎
- public void remove04() {
- for(Integer i:list){
- if(i==3) list.remove(i);
- }
- System.out.println(list);
- }
效果图如下:
报错显示:java.util.ConcurrentModificationException (当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。)
将方法点进去查看源码会发现在next、remove方法中都会调用checkForConmodification的方法。
若modCount不等于expectedModCount 就会报ConcurrentModificationException
但是在删除的时候是通过ArrayList的remove方法去操作的,不是Itr内部的那个删除方法去操作的。remove()函数会调用fastRemove()函数,使得modCount的值自增1.然而,for循环下一次调用Itr.next(),Itr.next()调用Itr.checkForComodification()时,会发现,modCount和expectedModCount两个值不相等!因为在这个删除操作的过程中没有对expectedModCount重新赋值,所以就抛出异常了。
- public boolean remove(Object o) {
- if (o == null) {
- for (int index = 0; index < size; index++)
- if (elementData[index] == null) {
- fastRemove(index);
- return true;
- }
- } else {
- for (int index = 0; index < size; index++)
- if (o.equals(elementData[index])) {
- fastRemove(index);
- return true;
- }
- }
- return false;
- }
-
-
- private void fastRemove(int index) {
- modCount++;
- int numMoved = size - index - 1;
- if (numMoved > 0)
- System.arraycopy(elementData, index+1, elementData, index,
- numMoved);
- elementData[--size] = null; // Let gc do its work
- }
为了达到效果,在原本数据中添加一条数据
- List<Integer> list=new ArrayList<Integer>();
- list.add(1);
- list.add(2);
- list.add(3);
- list.add(3);
- list.add(5);
- list.add(4);
方法
- public void remove04() {
- for(Integer i:list){
- if(i==5)
- list.remove(i);
- }
- System.out.println(list);
- }
刚开始cursor开始值是默认为0,0不等于size为true,将会进入到next()方法中,cursor会加一,当执行到5的时候,cursor等于5,5被删除了,并且size从原本的6变为5了,这个时候cursor等于size,就不会进入next()方法了。
- 1.It gets the iterator.
-
- 2.Checks for hasNext().
-
- public boolean hasNext()
-
- {
-
- return cursor != size(); // cursor is zero initially.
-
- }
-
- 3.If true, gets the next element using next().
-
- public E next()
-
- {
-
- checkForComodification();
-
- try {
-
- E next = get(cursor);
-
- lastRet = cursor++;
-
- return next;
-
- } catch (IndexOutOfBoundsException e) {
-
- checkForComodification();
-
- throw new NoSuchElementException();
-
- }
-
- }
-
- final void checkForComodification()
-
- {
-
- // Initially modCount = expectedModCount (our case 5)
-
- if (modCount != expectedModCount)
-
- throw new ConcurrentModificationException();
-
- }
5️⃣第五种:通过迭代器进行删除1✅
- public void remove05() {
- Iterator<Integer> it=list.iterator();
- while(it.hasNext()){
- if(it.next()==3){
- it.remove();
- }
- }
- System.out.println(list);
- }
6️⃣第六种::通过迭代器进行删除2❎
- public void remove06() {
- Iterator<Integer> it=list.iterator();
- while(it.hasNext()){
- Integer value=it.next();
- if(value==3){
- list.remove(value);
- }
- }
- }
效果图如下:
报错显示:java.util.ConcurrentModificationException (当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。)原因查看第四种方法
删除的参数是基本型的整数
- public void remove07() {
- list.remove(2);
- System.out.println(list);
- }
效果图如下:
若想删除对象类型的2 使用Integer.valueOf() 基本类型的2封装成对象类型的2
- public void remove07() {
- list.remove(Integer.valueOf(2));//基本类型的2封装成对象类型的2
- System.out.println(list);
- }
效果图如下