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,它们是一样的机制。
相关内容: