栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

List集合

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

List集合

在介绍常见集合类之前先给大家看看这个UML图(就如同设计师需要看懂设计稿一样)

 注意:List、Set、Map没有实现同一个接口 Map是一个单独的接口。它是键值对类型先有键(主键)再有值的 

什么是UML?

       UML是统一建模语言,是一种可视化的面向对象建模语言,是一种用来对真实世界物理进行建模的标准标记,用图形方式表现典型的面向对象系统的整个结构。它的作用域不局限于支持面向对象的分析与设计,还支持从需求分析开始的软件开发的全过程。

为了更好的看懂类图,大家可以点进下方链接了解了解UML类图几种关系的总结

UML类图几种关系的总结http://www.uml.org.cn/oobject/201609062.asp

List集合

特点:元素有序,且可重复

遍历:下标,foreach,迭代器

List list=new ArrayList();

	@Before
	public void setup() {
		  list.add(1);
		  list.add(2);
		  list.add(3);
		  list.add(3);
		  list.add(4);
	}
		 
	
	@Test
	public void list01() {
		for(Integer e:list){
			  System.out.println(e);
			}
	}
	
	@Test
	public void list02() {
		for(int i=0;i it = list.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
	

扩容:

  1. 初始容量10,负载因子0.5,扩容增量0.5倍
  2. 新容量 = 原容量 + 原容量 * 0.5  , 如 ArrayList的容量为10,一次扩容后是容量为15

代码示例:

public void listKR()throws Exception {
		List list=new ArrayList();
		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 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类似。线程安全


ArrayList remove(删除) 的注意点 ❗❗❗

题目要求:删除集合中所有为3的元素

数据准备:为方便演示,需要有紧挨在一起的两个或多个相同的元素

List list=new ArrayList();
  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 

 效果图如下:

很显然只删除了一个3,这是为什么呢?因为当删除到元素3的时候下面元素的位置会往上移那么原先第二个3的位置就成4了 所以没有删除成功

 图形解读:

 2️⃣第二种:for循环遍历list删除时将i--✅

public void remove02() {
		for(int i=0;i 

 效果图如下:

当删除第一个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 list=new ArrayList();
  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 it=list.iterator();
		 while(it.hasNext()){
		  if(it.next()==3){
		   it.remove();
		  }
		}
		 System.out.println(list);
	}

6️⃣第六种::通过迭代器进行删除2❎

public void remove06() {
		Iterator 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);
	}

 效果图如下

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995212.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号