集合初识和用法——List(java)

本文介绍了List接口的特性,包括ArrayList、LinkedList和Vector三个主要实现类的详细对比。ArrayList基于数组,适合查找和修改,但在插入和删除时效率较低。LinkedList采用链表结构,增删速度快,但查找和修改较慢。Vector是线程安全的,但性能较低,通常不推荐使用。文章还简要提到了迭代器的重要性。
摘要由CSDN通过智能技术生成

List是一种有序、提供角标、一维数据列表、允许重复元素、允许null元素的集合。它是collection的一个子接口,其已知实现的子类且常用的有ArrayList、LinkedList和Vector。下面将对List的一些方法的使用和它的常用子类的方法的使用进行介绍。

List的方法测试和使用示例以及说明

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class Main {
	public static void main(String[] args) {
	//list也是一个接口,不能创建对象,只能创建其子类对象
		List<Integer> list=new ArrayList<Integer>();
		for(int i=0;i<10;i++){
	//这里调用的是list自己的add(int index, E element)方法,
	//也可以直接添加元素调用add(E e)方法,这是从collection接口继承来的方法
   //而这里用到了list提供角标的特性,在指定位置添加元素
			list.add(i,i);
		}
		System.out.println(list);
   //结果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		
   //调用dd(E e)方法,默认在列表的尾部添加
		list.add(10);
		System.out.println(list);
   //结果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		
   //get方法获取某个角标下的值,注意角标越界喔!
		System.out.println(list.get(10));
	//结果 10
	
	//在该集合中间某角标位置添加一个数,该位置的数并不会被覆盖,
	//而是从该位置起的元素到最后的元素都向后移一个位置,再把要添加的数添加进去,哪怕元素重复也会添加进去
	//注意:在指定添加位置的时候,位置下标的取值在[(该集合的首元素下标-1)且要大于等于零,该集合的长度]
	//如果指定的下标超过这个范围就会发生错误
		list.add(4,11);
		list.add(4,11);
		System.out.println(list);
	//结果 [0, 1, 2, 3, 11, 11, 4, 5, 6, 7, 8, 9, 10]
		
	//获得该集合的长度
		System.out.println(list.size());
	//结果 13
		
	  //indexOf方法,从左右往右获得指定元素的第一次出现的位置下标
		System.out.println(list.indexOf(11));
	 //结果 4
		
//lastIndexOf方法是获得指定元素的最后一次出现的位置下标,相当于是从后往前查找指定元素第一次出现的位置下标
		System.out.println(list.lastIndexOf(11));
	  //结果5
		
        //有两种remove方法
		//remove(int index)  移除列表中指定位置的元素
		//remove(Object e)   从此列表中移除第一次出现的指定元素
		//因为泛型E-Integer,所以的参数容易混淆
		//因此如果直接调用remove方法并传入一个值,我们自己可能想移出11这个元素,但是这里会默认是移出角标为11所对应的元素9
		System.out.println(list.remove(11));
	 //结果 9
		System.out.println(list);
	//结果  [0, 1, 2, 3, 11, 11, 4, 5, 6, 7, 8, 10]

	//因此要移出某个元素,必须创建该元素的对象再移出,但是它返回的结果是Boolean类型,表示是否移出成功
		System.out.println(list.remove(new Integer(11)));
	//结果 true
		System.out.println(list);
	//结果 [0, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10] ,当然只会移出一个

	//set方法用指定元素去替换指定位置的元素,这里是覆盖,元素不会移动
		list.set(0, 666);
		System.out.println(list);
	//结果  [666, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10] 
		
	//subList方法用于截取该集合的子串,需要指明从哪个位置开始,截取多少,
	//当然这个截取的大小不能超过集合总长,指定的位置不能越过集合的角标范围
	//这个方法只是截取复制出来,对原集合不受影响
		System.out.println(list.subList(0, 3));
	//结果  [666, 1, 2]
		System.out.println(list);
    //截取后原集合的结果不变 [666, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10]

		
	//list集合也有迭代器Iterator方法,用来遍历集合的元素
		
		//但是Iterator在迭代集合的过程中,对集合是不可进行修改的,即不能调用其相应的方法进行操作
		
	//这段代码虽然编译时不会报错,但是在运行时就会出错ConcurrentModificationException,表示不可修改
		
		/*Iterator<Integer> it=list.iterator();
		while(it.hasNext()){
			Integer number=it.next();
			if(number==3){
				//ConcurrentModificationException
				list.remove(new Integer(3));
			}else{
				System.out.println(number);
			}
		}*/

	//为解决这一问题,list接口增加了ListIterator方法,有两种选择:
	//可以获取ListIterator()方法,返回此列表元素的列表迭代器(按适当顺序)。
	//listIterator(int index)方法 ,返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
	  //因此,可以在迭代集合的过程中,通过ListIterator对集合进行修改
		ListIterator<Integer> it2=list.listIterator();
		while(it2.hasNext()){
			Integer number=it2.next();
			if(number==11){
			//这里的remove()方法是ListIterator内部的方法
				it2.remove();
			}else{
				System.out.println(number);
			}
		}
	//迭代完成的结果 [666, 1, 2, 3, 4, 5, 6, 7, 8, 10]
		System.out.println(list);
	//修改后的原集合 [666, 1, 2, 3, 4, 5, 6, 7, 8, 10]

	//当然list提供角标访问,可以直接用循环访问下标获取集合的元素
		for(int i=0;i<list.size();i++){
			System.out.println(list.get(i));
		}
	//结果  [666, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10]
	}
}

ArrayList<E>类

ArrayList基于数组实现的、且容量和大小是可变的、但是在线程上是不同步的(线程问题会在后面进行介绍)。

基于数组实现的链表的优点是:查改快;缺点为:增删慢。ArrayList的方法有很多,大多都和它的父接口中的方法用法相同(参照上面List中的方法和collection中的方法),下面是它的一些基本方法的测试和说明。

import java.util.ArrayList;

public class Main {
	public static void main(String[] args) {
		
		//这里还是采用Integer类来进行测试方便理解。因为ArrayList是一个类,因此可以创建自己的对象
		/*
		 * ArrayList()有三个构造方法:
		 * ArrayList()   构造一个初始容量为 10 的空列表。 
		 * ArrayList(Collection<? extends E> c)(该方法不常用)
		 *   构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。 
		 * ArrayList(int initialCapacity)  构造一个具有指定初始容量的空列表。 
		 */
	//这里创建的是一个指定初始容量为20的空列表对象
		ArrayList<Integer> list=new ArrayList<Integer>(20);
		for(int i=1;i<=10;i++){
			list.add(i); //add方法,将指定的元素添加到此列表的尾部。
		}
		System.out.println(list);
	//结果 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		
	 // trimToSize()方法,将此 ArrayList 实例的容量调整为列表的当前大小。
	//此方法不能用结果来测试,原因是size()方法是获取当前集合的有效元素的大小
	//在ArrayList当中没有获取当前容量的方法,因为这是在内存中处理的,并没有返回结果,因此无法根据结果来测试
		list.trimToSize();
	
	//ensureCapacity方法是, 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。
	//此方法与trimToSize方法相对,当trimToSize方法减少容量时ensureCapacity增加容量(也可以减少)
	//虽然在这里,我们看不到结果,但是还是将当前的容量改回来,方便后面的方法测试
		list.ensureCapacity(20);

	//clone()方法,返回此 ArrayList 实例的浅表副本。相当于把原列表复制一份到新的一个列表
	 //在复制时,还要进行强制转换,因为clone()方法返回的类型是object对象
		ArrayList<Integer> list2=(ArrayList<Integer>) list.clone();
		System.out.println(list2);
	//复制之后的list2结果  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		
	//调用equals方法比较两个列表的内容,结果为true
		System.out.println(list.equals(list2));
		
	//虽然内容一样,但是它还是两个对象,用==比较两个列表对象的地址,结果为false
		System.out.println(list==list2);
		
  //toArray()方法,按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;
	//返回数组的运行时类型是指定数组的运行时类型
		Object[] numbers=list.toArray();
	//通过toArray方法,将该列表转为数组,然后用遍历数组的方法进行遍历该列表的元素
		for(int i=0;i<numbers.length;i++){
			System.out.println(numbers[i]);
		}
	//结果 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
	}
}

LinkedList<E>类

LinkedList是基于链表实现、但即可当做列表使用、也可当做栈使用,还可当做双端队列使用,且它的线程也是不同步的

基于链表实现的列表的优点是:增删快;缺点为:查改慢,LinkedList与ArrayList同为List的子类,大多也都和它的父接口中的方法用法相同(参照上面List中的方法和collection中的方法),下面是它的一些基本方法的测试和说明。

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

public class Main {
	public static void main(String[] args) {
	//LinkedList可用于列表、堆栈和队列使用
		LinkedList<Integer> list=new LinkedList<Integer>();
		
	//当做列表使用
		for(int i=0;i<10;i++){
			list.add(i); //add方法,将指定元素添加到此列表的结尾。
		}
		System.out.println(list);
	//结果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
	
	//clear方法,从此列表中移除所有元素。
		list.clear();  
		System.out.println(list);
	//结果  []
		
		for(int i=0;i<10;i++){
   //addFirst方法,将指定元素插入此列表的开头。还有一个addLast方法, 将指定元素添加到此列表的结尾。
		//此方法既可以当做列表使用,也可当做堆栈使用
			list.addFirst(i);
		}
		System.out.println(list);
		
	//结果  [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
		list.clear();
		
	//当做堆栈使用
		for(int i=0;i<10;i++){
	//push方法,将元素推入此列表所表示的堆栈。
			list.push(i);	
		}
		System.out.println(list);
	//结果  [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
		list.clear();
		
	//当做队列使用
		for(int i=0;i<10;i++){
	//offer方法, 将指定元素添加到此列表的末尾(最后一个元素)。
    //与列表使用相同,还有offerFirst方法,在此列表的开头插入指定的元素
	//offerLast方法,在此列表末尾插入指定的元素。
			list.offer(i);	
		}
		System.out.println(list);
   //结果  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		
	//get方法,返回此列表中指定位置处的元素。此外还有:
	//getFirst():返回此列表的第一个元素。
	//getLast():返回此列表的最后一个元素
		System.out.println(list.get(3));
	//结果 3
		
		
	 //在LinkedList中,提供descendingIterator()方法,返回以逆向顺序在此双端队列的元素上进行迭代的“迭代器”。
	 //默认从表尾开始遍历
		Iterator<Integer> it=list.descendingIterator();
		while(it.hasNext()){
			System.out.print(it.next());
		}
	//结果 9876543210
		System.out.println();
	 //除此之外,LinkedList也存在listIterator(int index)方法,
	 //返回此列表中的元素的“列表迭代器”(按适当顺序),从列表中指定位置开始。可以默认从表头开始遍历或者指定起始位置开始
	//在ListIterator<E>接口中,比Iterator<E>接口多了一种遍历的方法,逆序遍历
	//previous(): 返回列表中的前一个元素。
	//hasPrevious(): 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。
	//如果默认从表头开始 则调用previous方法没元素,只能用next方法
	//如果从指定位置开始,可以用previous方法,也可以用next方法
		ListIterator<Integer> it2=list.listIterator(5);
		while(it2.hasPrevious()){
			System.out.print(it2.previous());
		}
	//结果  43210
		
	//注意:Iterator 只能从表头开始 且只能用next
	}
}

Vector<E>类

Vector是基于数组的、可变长的、线程同步的集合、(同步意味着线程安全->有函数锁->每次调用函数得先判断锁是否被占用,一般在多线程的情况下用和StringBuffer比较像),缺点是都慢,但是一般这个借口不常用,常用的是它的实现子类Stack,基于栈实现,Vector的改装。关于Stack的介绍和方法的使用,在前面已经介绍过,请参考:

https://blog.csdn.net/weixin_45432742/article/details/99850913

至此有关List的子类和方法的使用就介绍到这里。现在我们来总结一下迭代器,如图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值