Java中List和Set集合的使用

Java中List和Set集合的使用

ArrayList类

在开始介绍其他集合及其父类和接口前,首先介绍ArrayList类,因为ArrayList与我们熟悉的数组非常相似,易于理解;且有助于在后续讲到父类接口时做代码示例演示。

1.什么是ArrayList:

ArrayList就是传说中的动态数组(可变数组),用MSDN中的说法,就是Array的复杂版本。ArrayList继承自List,该类已经把所有抽象方法进行了重写。

2.ArrayList和数组的比较:

1.数组的长度是固定的,集合的长度是可变的;
2.数组可存基本类型和引用类型,集合只可存引用类型。

3.如何使用ArrayList :

最简单的例子(这是一个简单的例子,虽然没有包含ArrayList所有的方法,但是可以反映出ArrayList最常用的用法):

ArrayList arr = new ArrayList(); 
for( int i=0;i <10;i++ ) //给数组增加10个Int元素 
	arr.Add(i); 
//程序做一些处理 
arr.RemoveAt(5);//将第6个元素移除 
for( int i=0;i <3;i++ ) //再增加3个元素 
	arr.Add(i+25); 
Int32[] values = (Int32[]) arr.ToArray(typeof(Int32));//返回ArrayList包含的数组

继续看示例1:ArrayList存储int类型数据

//ArrayList集合存储3个int类型元素
public static void main(String[] args) {
   
		ArrayList<Integer> arr = new ArrayList<Integer>();
		arr.add(111);
		arr.add(222);
		arr.add(333);
		for (int i = 0; i < arr.size(); i++) {
   
			System.out.println(arr.get(i));
		}
}

由上面ArrayList与数组比较中提到的,集合本身不存储基本类型数据,但由于java装箱、拆箱的机制,这里自动将int转换为了引用类型。

示例2:集合存储自定义的Person类的对象

ArrayList集合存储3个Person类型元素
public static void main(String[] args) {
   

		ArrayList<Person> arr = new ArrayList<Person>();
		arr.add(new Person("老何"));
		arr.add(new Person("小舒"));
		arr.add(new Person("王明"));
		for (int i = 0; i < arr.size(); i++) {
   
			Person p = arr.get(i);
			System.out.println(p);
		}
}
// Person类为:
class Person {
   
	private String name;

	public Person(String name) {
   
		this.name = name;
	}

	public String toString() {
   
		return " Person [name:" + name + "]";
	}
}

这里打印时输出的不是对象的内存地址,而是默认调用了重写了的Object类的toString()方法,输出为:

Person [name:老何]
Person [name:小舒]
Person [name:王明]

Object类是所有类的父类,若没有使用extends关键字明确表示该类继承哪个类,那么它就默认继承Object类;Object类的toString方法默认(没有被子类重写)输出的是内存地址的字符串。

4.ArrayList的构造方法:

ArrayList提供了三个构造器:

修饰语和类型 方法 描述
public ArrayList() 默认的构造器,将会以默认(16)的大小来初始化内部的数组
public ArrayList(Collection) 用一个Collection对象来构造,并将该集合的元素添加到ArrayList
public ArrayList(int) 用指定的大小来初始化内部的数组

注:示例中出现了类名后有<>的形式,这是Java中的泛型,下文会做详细介绍,这里只需知道它的作用是限制数据的存储类型。

上面只是通过一些简单的示例来演示ArrayList的用法,没有做详细的介绍和分析。由于它的大多数方法都是重写的其父接口的公用方法,为了避免赘述,所以ArrayList类的其他方法详情请参考下面Collection接口中的方法介绍。

Collection接口中的方法

集合Collection中的方法是集合中所有实现类必须拥有的方法。

常用方法摘要:

修饰语和类型 方法 描述
boolean add(E e) 将对象元素添加到调用此方法的Collection集合中
boolean addAll(Collection<? extends E> c) 将指定Collection中的所有元素都添加到此Collection中
void clear() 清空Collection中的所有元素(删的是里面元素,而不是容器本身)
boolean contains(Object o) 判断对象o是否存在于Collection集合中
int size() 返回集合中的元素个数
Object[] toArray() 将集合中的元素转换为数组中的元素,集合转数组
boolean[] remove(Object o) 移除集合中指定的元素
boolean equals(Object o) 将指定的对象与此集合进行比较以获得相等性
boolean isEmpty() 如果此集合不包含元素,则返回 true
Iterator< E > iterator() 返回此集合中的元素的迭代器。

表中列出了Collection接口的一些常用发法,其他不常用的方法如int hashCode() 、boolean removeAll(Collection<?> c) 等如需使用请自行了解。

Iterator迭代器

发现没有Collection方法表中最后一个方法为返回迭代器(^ o ^),也就是说:Collection的子类或实现类重写了Iterator接口中的iterator()方法,返回了Iterator接口的实现类的对象。所以接着介绍什么是迭代器?

关于 迭代器的使用 请点击跳转到Java中迭代器的使用查看。

泛型

关于 泛型的知识 请点击跳转到Java中泛型的使用查看。

到此,集合的共性已经介绍得差不多了,也算是做了大量准备工作,接下来就可以快速的介绍各个子类的特性,进而全面的了解集合体系。

List接口

List接口继承自Collection接口,称为有序的Collection(也称为:序列)。

1.特点:

1.List的序列并不是指以升降序排序,而是指存储的顺序与取出的顺序相同。
2.此接口的用户可以对列表中每个元素的插入位置进行精确控制。
3.用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
4.List集合允许存储重复元素。

2.特有方法:

由于List接口继承自Collection接口,所以它的一部分抽象方法和它的父接口Collection是一样的。其公共方法我们已经了解,那么只需关注List接口自己特有的方法。又因为List接口带有索引这个特点,所以可以想到,在方法当中,带有索引的应该就是List自身特有的方法:

修饰语和类型 方法 描述
boolean add(E e) 向列表的尾部添加指定的元素
void add(int index, E element) 在列表的指定位置插入指定元素
E get(int index) 返回列表中指定位置的元素
E remove(int index) 移除列表中指定位置的元素,返回值为删除的这个元素
boolean remove(Object o) 从此列表中移除第一次出现的指定元素(如果存在)
E set(int index, E element) 用指定元素替换列表中指定位置的元素,返回值为修改前的元素

由于List集合拥有索引,因此List集合迭代方式除了使用迭代器外之外,还可以使用索引进行迭代。

for(int i = 0; i < list.size(); i++) {
		String str = list.get(i);
		System.out.println(str);
}

前文对集合的使用展示了大量示例,这里将不再做更多的演示,相信大家一看到方法介绍基本就知道该怎么用了。注:在做带有索引的操作时,要注意防止越界问题(做操作的索引位置不能超过最大索引)

补充:这里还有个知识点是:迭代器的并发修改异常,就是在遍历集合的过程中,使用了集合方法,对集合元素进行了修改,这种操作是不允许的,会抛出java.util.ConcurrentModificationException异常,所以我们要避免出现这种操作。

3.实现类

List的接口下有很多的实现类,它们都具有List的所有特点,但它们存储元素所采用的结构方式是不同的,这样就导致了这些集合有它们各自的特点,供给我们在不同的应用环境下进行使用。数据存储的常用结构有:堆栈、队列、数组和链表。

ArrayList: ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。很多程序员开发时非常随意地使用ArrayList完成任何需求是不严谨的,不提倡。

LinkedList: LinkedList集合数据存储的结构是链表结构。元素的添加、删除方便。实际开发中对一个集合元素的添加与删除经常会涉及到首尾操作,因此LinkedList提供了大量首尾操作的方法:

修饰语和类型 方法 描述
void addFirst(E e) 将指定元素插入此列表的开头
void addLast(E e) 将指定元素添加到此列表的结尾
E getFirst() 返回此列表的第一个元素
E getLast() 返回此列表的最后一个元素
E removeFirst() 移除并返回此列表的第一个元素
E removeLast() 移除并返回此列表的最后一个元素
E pop() 从此列表所表示的堆栈处弹出一个元素
void push(E e) 将元素推入此列表所表示的堆栈
boolean isEmpty() 如果列表不包含元素则返回true

在开发时,LinkedList集合也可以作为堆栈、队列的结构使用。

注意:在使用LinkedList集合的特有方法时,必须使用子类对象,而不能使用多态调用,因为List接口中没有以上的那些功能。

Set接口

在介绍Collection接口时,提到Collection中可以存放重复元素,也可以不存放重复元素,另外我们还知道List中是可以存放重复元素的。那么不重复元素存放到哪里呢?没错,那就是Set接口,它里面的集合,所存储的元素就是不重复的。

1.方法:

Set接口的方法与它的父亲Collection接口完全一样,和它兄弟List接口不同(带索引),所以Set集合的方法不需要介绍了,因为它的爹:Collection集合,我们已经了解~

2.实现类

HashSet: 此类实现Set接口,由哈希表(实际上是一个HashMap示例)支持。它不保证元素的迭代顺序,特别是它不保证该顺序恒久不变,如存的时候是1,2,3,取出时就不一定了。另外此类允许使用null元素。

特点:
1.不存储重复元素;
2.没有索引;
3.无序集合,存储和取出的顺序不同。

LinkedHashSet: 此类继承自HashSet,被称为基于链表的哈希表实现。自身特性是:具有顺序,存储和取出的元素顺序是相同的。并且它含有父类的特性:不允许含有重复的元素。注意区分它和父亲HashSet的共同点和差异。

补充1: 感兴趣的朋友还可以自行去了解一下ArrayList集合和HashSet集合判断对象是否重复的原理是什么?这其实和它们调用自己的方法contains、equals和判断元素类型的hashCode值有关,这里不做叙述。

补充2: 前面继承图中我们已经知道集合分Collection和Map两大派系,而Set虽然属于Collection的子接口,但其本质上依赖于Map集合。所以学会了Set就相当于学会了Map,它们是一样的机制。

相关内容:

Java中集合的使用
Java中Map集合的使用

本文来源MrKorbin,由架构君转载发布,观点不代表Java架构师必看的立场,转载请标明来源出处:https://javajgs.com/archives/25327

发表评论