黑马程序员-集合类Collection之List接口

-----------android培训java培训、java学习型技术博客、期待与您交流! ------------


一、集合类


1、定义

面向对象对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储。集合就是存储对象最常用的一种方式。

集合是一个接口,将每种容器的共性提取,形成的一个体系。


2、数组和集合都是容器,两者有何不同?


(1)数组长度固定,而集合长度是可变的。
(2)数组值可以存储对象,还可以存储基本数据类型;而集合只能存储对象。
(3)数组存储数据类型是固定的,而集合存储的数据类型不固定。


3、集合类的特点:


(1)集合只能存储对象
(2)集合的长度是可变的
(3)集合可以存储不同类型的对象


4、数据结构:


由于每种容器对数据的存储方式都各不相同,所以出现了不同的容器。此种存储方式称之为数据结构。


二、集合框架的构成及分类




如上图,事实上只有4个基本的容器:Map,List ,Set,Queue。它们各有2到3个实现版本。常用的容器用黑色粗线框表示。

点线框表示接口;实线框表示具体的类;带有空心箭头的点线表示一个特定的类实现了一个接口;实心箭头表示某个类可以生成箭头所指向类的对象。


三、Collection接口


1、定义:

Collection是描述所有序列容器的共性的根接口,它可能会被认为是一个“附属接口”,即因为要表示其他若干个接口的共性而出现的接口,不承担产生具体容器的任务。


2、子接口:

Collection接口有两个子接口:List(列表),Set(集)。

|--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引;可以存储重复元素。
|--Set:无序(存入和取出顺序有可能不一致);不可以存储重复元素,必须保证元素唯一性。


3、共性方法:


(1)添加:

add(object):添加一个元素
addAll(Collection) :添加一个集合中的所有元素。


(2)删除:
clear():将集合中的元素全删除,清空集合。
remove(obj) :删除集合中指定的对象。注意:删除成功,集合的长度会改变。
removeAll(collection) :删除部分元素。部分元素和传入Collection一致。


(3)判断:
boolean contains(obj) :集合中是否包含指定元素 。
boolean containsAll(Collection) :集合中是否包含指定的多个元素。
boolean isEmpty():集合中是否有元素。 


(4)获取元素个数:
int size():集合中有几个元素。


(5)取交集:
boolean  retainAll(Collection) :对当前集合中保留和指定集合中的相同的元素。如果两个集合元素相同,返回flase;如果retainAll修改了当前集合,返回true。

(6)获取集合中所有元素:
Iterator  iterator():迭代器
迭代是取出集合中元素的一种方式。因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。

(7)将集合变成数组:
 T[ ]   toArray(T[ ]  a):返回包含此collection中所有元素的数组。


四、迭代器


1、定义:

迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必知道或关心该序列底层的结构。


2、迭代器的由来和实现机制:

因为每个集合中元素的取出方式都不一样,于是就把元素的取出方式进行抽取,并定义在集合内部,这样取出方式就可以直接访问集合内部的元素;而每个容器的数据结构不同,所以取出动作的细节也不一样,但是有共性内容:判断和取出。那么就将共性内容进行抽取,从而形成了接口Iterater。


3、迭代器的真正威力:

能够将遍历序列的操作与序列底层的结构分离,从而统一了对容器的访问方式。

 

4、注意细节:

(1)迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。也就是在迭代循环中调用一次next方法一次就要hasNext判断一次,比如语句 sop(it.next()+"..."+it.next())会发生上述异常。
(2)迭代器的next方法返回值类型是Object,所以要记得类型转换,应用泛型后就不用强转。

 

5、格式:

Iterator it = collection.iterator();
while(it.hasNext())
{
     Collection c = it.next()
     System.out.println(c));
}


五、List接口


1、定义:

List本身是Collection接口的子接口,具备了Collection的所有方法。


2、特点:

List的特有方法都有索引,这是该集合最大的特点。

有序(元素存入集合的顺序和取出的顺序一致),元素都有索引;可以存储重复元素。


3、子类:

|--ArrayList:底层的数据结构是数组,线程不同步,查询元素的速度非常快,但增删慢。
|--LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快,但查询慢。
|--Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢,ArrayList替代了Vector。

 

具体原理:

|--ArrayList:底层是数组结构,也是支持长度可变数组的。是不同步的。替代了Vector.因为效率高,单线程不必判断锁浪费资源。 查询效率很高(数据空间是连续的,并有角标)。 但是增删的效率很低(增删会改变容器的长度。而且其后的每个元素都要向前或者向后依次移动一位或多位)。
|--LinkedList:底层是链接列表结构,简称链表结构。是不同步的。这个结构的好处:对元素的增删非常效率很高(可以直接通过改变链表链上的元素中的头指向和尾指向)。 查询的效率很低(要从头到尾顺着路径查)。

4、特有方法:


(1)添加:
add(index,element) :在指定的索引位插入元素。
addAll(index,collection) :在指定的索引位插入一堆元素。


(2)删除:
remove(index) :删除指定索引位的元素。 返回被删的元素。


(3)修改:
Object set(index,element) :对指定索引位进行元素的修改。


(4)查找:
Object get(index) :通过索引获取指定元素。
int indexOf(obj) :获取指定元素第一次出现的索引位,如果该元素不存在返回-1;  所以,通过-1,可以判断一个元素是否存在。
int lastIndexOf(Object o) :反向索引指定元素的位置。
List subList(start,end) :获取子列表。

(5)获取所有元素:
ListIterator listIterator():list集合特有的迭代器。
List集合支持对元素的增、删、改、查。
List集合因为角标有了自己的获取元素的方式: 遍历。

//获取List集合中所有元素的两种方式

public static void getAllElements(List list){
	list.add("abc1");
	list.add("abc7");
	list.add("abc2");
	list.add("abc4");

	//第一种:迭代器。
	Iterator it = list.iterator();
	while(it.hasNext()){
	System.out.println(it.next());
	}

	//第二种:遍历。通过索引完成。
	for(int x=0; x<list.size(); x++){
	System.out.println("get:"+list.get(x));
	}

}

 


5、ListIterator


(1)定义:

ListIterator是List集合特有的迭代器。ListIterator是Iterator的子接口。该接口只能通过List集合的listIterator方法获取。


(2)用Iterator迭代时操作元素会发生的问题:
在进行list列表元素迭代的时候,如果想要在迭代过程中,想要通过集合对象的方法操作集合中的元素的时候,比如添加新元素,会发生ConcurrentModificationException并发修改异常。


(3)导致上述问题的内在原因是:
集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代过程中,如果用集合对象对元素进行了修改,迭代器对象是不知道的,所以会出现异常情况。


(4)解决方法
既然是在迭代中对元素进行操作,用迭代器的方法最为合适。可是Iterator中只有hasNext(判断),next(查找),remove(删除)方法。如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该列表迭代器接口具备了对元素的增、删、改、查的动作,以及双向访问。
ListIterator it = list.listIterator;      //取代Iterator it = list.iterator;

 

6、注意细节:

(1)List集合里面的元素因为是带角标,所以List集合里面的元素都是有序的,另外List集合可以包含重复元素,也可以包含null。
(2)List集合有迭代器Iterator,还有一个特有迭代器列表ListIterator
(3)List集合中判断元素是否相同都是用equals方法,无论contains、remove都依赖equals方法。
 比如往ArrayList集合里面存放学生,同名同年龄视为同一个人,此时就需要在学生类复写Object类里面的equals方法(非常重要!!!要注意!!)

7、练习


练习1:去除ArrayList集合中的重复元素。

import java.util.*;

class ArrayListTest {
	public static void sop(Object obj) {
		System.out.println(obj);
	}

	public static ArrayList singleElement(ArrayList al) {
		// 定义一个临时容器。
		ArrayList newAl = new ArrayList();

		Iterator it = al.iterator();

		while (it.hasNext()) {
			Object obj = it.next();

			if (!newAl.contains(obj))// 判断是否存在这个元素
				newAl.add(obj);
		}
		return newAl;
	}

	public static void main(String[] args) {
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java01");
		al.add("java02");
		al.add("java01");
		al.add("java03");
		sop(al);// 打印原集合
		al = singleElement(al);
		sop(al);// 打印去除重复元素集合
	}
}

/*output:
[java01, java02, java01, java02, java01, java03]
[java01, java02, java03]
*/


练习2:将自定义对象作为元素存到ArrayList集合中,并去除重复元素。

/*
比如:存人对象。同姓名同年龄,视为同一个人。为重复元素。

思路:
1,对人描述,将数据封装进人对象。
2,定义容器,将人存入。
3,取出。
List集合判断元素是否相同,依据是元素的equals方法。
 */

import java.util.*;

class Person {
	private String name;
	private int age;

	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public boolean equals(Object obj) {
		if (!(obj instanceof Person))
			return false;
		Person p = (Person) obj;// 将object类型强制转换成Person
		return this.name.equals(p.name) && this.age == p.age;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}
}

class ArrayListTest2 {
	public static void sop(Object obj) {
		System.out.println(obj);
	}

	public static ArrayList singleElement(ArrayList al) {
		// 定义一个临时容器。
		ArrayList newAl = new ArrayList();

		Iterator it = al.iterator();

		while (it.hasNext()) {
			Object obj = it.next();

			if (!newAl.contains(obj))
				newAl.add(obj);

		}
		return newAl;
	}

	public static void main(String[] args) {
		ArrayList al = new ArrayList();

		al.add(new Person("lisi01", 30));// al.add(Object obj);
										// Object obj = new Person("lisi01",30);
		al.add(new Person("lisi02", 32));
		al.add(new Person("lisi02", 32));
		al.add(new Person("lisi04", 35));
		al.add(new Person("lisi03", 33));
		al.add(new Person("lisi03", 35));
		al = singleElement(al);
		Iterator it = al.iterator();

		while (it.hasNext()) {
			Person p = (Person) it.next();
			sop(p.getName() + "::" + p.getAge());
		}
	}
}

/*output:
lisi01::30
lisi02::32
lisi04::35
lisi03::33
lisi03::35
*/

练习3:使用LinkedList模拟一个堆栈数据结构。

/*
使用LinkedList模拟一个堆栈数据结构。
堆栈:先进后出  如同一个杯子。
 */
import java.util.*;

class MyStack {
	private LinkedList storage;

	MyStack() {
		storage = new LinkedList();
	}

	// 队头插
	public void push(Object obj) {
		storage.addFirst(obj);
	}

	public Object pop() {
		return storage.removeFirst();
	}

	public boolean empty() {
		return storage.isEmpty();
	}

	public static void main(String[] args) {

		MyStack myStack = new MyStack();

		myStack.push("java01");
		myStack.push("java02");
		myStack.push("java03");
		myStack.push("java04");

		while (!myStack.empty()) {
			System.out.println(myStack.pop());
		}
	}
}

/*output:
java04
java03
java02
java01
*/

练习4:使用LinkedList模拟一个队列数据结构。

/*
使用LinkedList模拟一个队列数据结构。
队列:先进先出 First in First out  FIFO 如同一个水管。
 */
import java.util.*;

public class MyQueue {
	LinkedList storage = new LinkedList();

	// 队尾插,与堆栈的不同就在于此
	public void myAdd(Object o) {
		storage.addLast(o);
	}

	// 队头取, 取完并删除
	public Object myGet() {
		return storage.removeFirst();
	}

	public boolean isEmpty() {
		return storage.isEmpty();
	}

	public static void main(String[] args) {

		MyQueue myQueue = new MyQueue();

		myQueue.myAdd(1);
		myQueue.myAdd(2);
		myQueue.myAdd(3);
		myQueue.myAdd(4);

		while(!myQueue.isEmpty())
			System.out.println(myQueue.myGet());
	}
}

/*output:
1
2
3
4
*/


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值