Java中的数组与集合类的使用,系列文章:
《Java中String、Array、List的相互转换工具类》
《Java8使用Stream流实现List列表的查询、统计、排序、分组》
《Java实现List集合的排序:Comparable接口、Comparator接口、stream().sorted()方法的使用》
Java中提供了不同的集合类,这些类具有不同的存储对象的方式,并提供了相应的方法以方便用户对集合进行遍历、添加、删除以及查找指定的对象。
1、集合类概述
Java语言的java.util包中提供了一些集合类,这些集合类又被称为容器。提到容器不难会想到数组,集合类与数组不同之处是,数组的长度是固定的,集合的长度是可变的;数组用来存放基本类型的数据,集合用来存放对象的引用。常用的集合有List集合、Set集合、Map集合,其中List与Set实现了Collection接口。各接口还提供了不同的实现类。上述集合类的继承关系如下图。
2、Collection接口
Collection接口是层次结构中的根接口。构成Collection的单位,被称之为元素。Collection接口通常不能直接使用,但该接口提供了添加元素、删除元素、管理数据的方法。由于List接口与Set接口都继承了Collection接口,因此这些方法对List集合与Set集合是通用的。
Collection接口的常用方法:
方法 | 说明 |
---|---|
boolean add(E e) | 将指定的对象添加到该集合中。 |
boolean remove(Object o) | 将指定的对象从该集合中移除。 |
boolean isEmpty() | 返回boolean值,用于判断当前集合是否为空。 |
Iterator<E> iterator() | 返回在此collection的元素上进行迭代的迭代器。用于遍历集合中的对象。 |
int size() | 返回int类型,获取该集合中元素的个数。 |
boolean contains(Object o) | 判断列表中是否存在指定元素。 |
通常遍历集合,都是通过迭代器(Iterator)来实现。Collection接口中的iterator()方法可返回在此Collection进行迭代的迭代器。
关于 Java 中迭代器(Iterator)的使用,请点击并浏览本博客文章:《Java中迭代器(Iterator)的使用》
示例:实例化集合对象,并向集合中添加元素,最后将集合中的对象以String形式输出。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 集合对象的使用示例
*
* @author pan_junbiao
*
*/
public class Muster
{
public static void main(String[] args)
{
// 实例化集合类对象
Collection<String> list = new ArrayList<String>();
// 向集合添加数据
list.add("pan_junbiao");
list.add("KevinPan");
list.add("pan_junbiao的博客");
// 创建迭代器
Iterator<String> it = list.iterator();
// 判断是否有下一个元素
while (it.hasNext())
{
// 获取集合中元素
String str = (String) it.next();
System.out.println(str);
}
// 判断列表中是否存在指定元素
if (list.contains("pan_junbiao的博客"))
{
System.out.println("存在");
} else
{
System.out.println("不存在");
}
}
}
注意:Iterator的next()方法返回的是Object类型。
执行结果:
3、List集合
List接口继承了Collection接口,因此包含Collection中的所有方法。List是有序集合,允许有相同的元素。此外,List接口还定义了以下两个非常重要的方法。
方法 | 说明 |
---|---|
get(int index) | 获得指定索引位置的元素。 |
set(int index , Object obj) | 将集合中指定索引位置的对象修改为指定的对象。 |
List接口的常用实现类有ArrayList、LinkedList和Vector。
3.1 ArrayList类
ArrayList是List接口的一个实现类,它实现了可变大小的数值,允许所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。
优点:在进行随机访问和遍历时,ArrayList提供更好的性能。
缺点:是向指定的索引位置插入对象或删除对象的速度较慢。
语法:
List<E> list = new ArrayList<>();
示例:实例化ArrayList集合对象,并对该集合进行元素的添加、删除、遍历的操作。
/**
* ArrayList集合对象的使用示例
*
* @author pan_junbiao
*
*/
public class Gather
{
public static void main(String[] args)
{
// 创建ArrayList集合对象
List<String> list = new ArrayList<>();
// 添加元素
list.add("pan_junbiao");
list.add("KevinPan");
list.add("pan_junbiao的博客");
// 删除元素
list.remove(1);
// 遍历集合(方式一)
System.out.println("遍历集合(方式一):");
for (int i = 0; i < list.size(); i++)
{
System.out.println(list.get(i));
}
// 遍历集合(方式二)
System.out.println("\n遍历集合(方式二):");
for (String s : list)
{
System.out.println(s);
}
}
}
执行结果:
3.2 LinkedList类
LinkedList是List接口的一个实现类,它提供了额外的addFirst()、addLast()、removeFirst()、removeLast()等方法,可以在LinkedList首部或者尾部进行插入或者删除操作。
优点:LinkedList类采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象时,使用LinkedList类实现的List集合的效率较好。
缺点:对于随机访问集合中的对象,使用LinkedList类实现List集合的效率较慢。
语法:
List<E> list = new LinkedList<>();
LinkedList类的一些特殊方法:
方法 | 说明 |
---|---|
void addFirst(Object o) | 在列表的首部添加元素。 |
void addLast(Object o) | 在列表的尾部添加元素。 |
Object getFirst() | 返回列表中的第一个元素。 |
Object getLast() | 返回列表中的最后一个元素。 |
Object removeFirst() | 删除并返回列表中的第一个元素。 |
Object removeLast() | 删除并返回列表中的最后一个元素。 |
3.3 Vector类
Vector类具有一个与数组类似的数据结构,此结构是动态的,可以存储对象引用。一个Vector实例可以存储的元素为不同类的实例。其父类为AbstractList,它实现List接口。
Vector类提供4个构造方法:
构造方法 | 说明 |
---|---|
Vector() | 创建一个Vector对象。其初始容量为10,容量增量为0。 |
Vector(int initialCapacity) | 创建一个Vector对象,其初始容量有 initialCapacity 指定,其容量增量为0。 |
Vector(int initialCapacity, int capacityIncrement) | 创建一个Vector对象,其初始容量有 initialCapacity 指定,其容量增量由 capacityIncrement指定。 |
Vector(Collection<? extends E> c) | 创建一个包含给定集合元素的Vector对象。 |
Vector类的常用方法:
方法 | 说明 |
---|---|
void addElement(E obj) | 将指定的元素插入 Vector 对象的末尾处。 |
int capacity() | 返回 Vector 对象的元素数或容量。 |
boolean contains(Object o) | 如果 Vector 对象包含指定对象,返回 true。 |
void copyInto(Object[] anArray) | 将 Vector 的元素复制到指定的数组中。 |
E elementAt(int index) | 检索位于指定索引处的元素。 |
E firstElement() | 返回 Vector 中的第一个元素。 |
int indexOf(Object o) | 搜索 Vector 对象并返回第一个匹配对象的索引。 |
E lastElement() | 返回 Vector 对象中的最后一个元素。 |
void removeAllElements() | 从 Vector 对象中删除所有元素。 |
void setElementAt(E obj, int index) | 使用指定对象替换位于指定索引处的对象。 |
void insertElementAt(E obj, int index) | 将元素添加到 Vector 对象中 index 指定的位置。 |
String toString() | 返回表示 Vector 内容的格式化字符串。 |
int size() | 返回int类型,获取该集合中元素的个数。 |
void setSize(int newSize) | 根据 size 的值设置 Vector 对象的大小。 |
示例:Vector类的使用。
import java.util.Vector;
/**
* Vector类的使用示例
*
* @author pan_junbiao
*
*/
public class vectorTest
{
public static void main(String[] args)
{
// 创建一个Vector对象
Vector<String> userVector = new Vector<String>();
// 添加值
userVector.add("Kevin");
userVector.add("William");
userVector.add("Andrew");
// 插入值
userVector.insertElementAt("pan_junbiao", 0);
userVector.insertElementAt("pan_junbiao的博客", 4);
// 显示值
System.out.println("*****************************");
System.out.println("显示内容:");
for (String item : userVector)
{
System.out.print(item + "; ");
}
System.out.println("\n大小:" + userVector.size());
// 搜索值
System.out.println("*****************************");
System.out.println("搜索内容:");
String serchUser = "pan_junbiao的博客";
if (userVector.contains(serchUser))
{
System.out.println("在索引" + userVector.indexOf(serchUser) + " 中找到:" + serchUser);
}
// 删除值
userVector.removeElement("William");
System.out.println("*****************************");
System.out.println("删除用户名为William后的内容:");
for (String item : userVector)
{
System.out.print(item + "; ");
}
System.out.println("\n大小:" + userVector.size());
// 使用Vector类的其他方法
System.out.println("*****************************");
System.out.println("第一个元素为:" + userVector.firstElement());
System.out.println("最后一个元素为:" + userVector.lastElement());
System.out.println("默认容量:" + userVector.capacity());
}
}
执行结果:
4、Set集合
Set集合中的对象不按特定的方式排序,只是简单地把对象加入集合中,但Set集合中不能包含重复对象。Set集合由Set接口和Set接口的实现类组成。Set接口继承了Collection接口,因此包含Collection接口的所有方法。
Set接口常用的实现类有HashSet类与TreeSet类。
HashSet类实现Set接口,有哈希表(实际上是一个HashMap实例)支持。它不保证Set的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用null元素。
TreeSet类不仅实现了Set接口,还实现了java.util.SortedSet接口,因此,TreeSet类实现的Set集合在遍历集合时按照自然顺序递增排序,也可以按照指定比较强递增排序,即可以通过比较器对用TreeSet类实现的Set集合中的对象进行排序。
TreeSet类增加的方法:
方法 | 说明 |
---|---|
E first() | 返回此 Set 中当前第一个(最低)元素。 |
E last() | 返回此 Set 中当前最后一个(最高)元素。 |
Comparator<? super E> comparator() | 返回对此 Set 中的元素进行排序的比较器。如果此 Set 使用自然顺序,则返回null。 |
SortedSet<E> headSet(E toElement) | 返回一个新的 Set 集合,新集合是 toElement (不包含)之前的所有对象。 |
SortedSet<E> subSet(E fromElement, E toElement) | 返回一个新的 Set 集合,是 fromElement (包含)对象与 toElement (不包含)对象之间的所有对象。 |
SortedSet<E> tailSet(E fromElement) | 返回一个新的 Set 对象,新集合包含对象 fromElement(包含)之后的所有对象。 |
示例:Set集合的示例,创建StuInfo类,实现 Comparable 接口,重写该接口中的 compareTo()方法。
import java.util.HashSet;
import java.util.TreeSet;
/**
* Set集合的示例
*
* @author pan_junbiao
*
*/
public class StuInfo implements Comparable<Object> // 创建类实现 Comparable 接口
{
int id; // 编号
String name; // 姓名
// 构造方法
public StuInfo(int id, String name)
{
this.id = id;
this.name = name;
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
// 重写排序方式
public int compareTo(Object o)
{
StuInfo stuInfo = (StuInfo) o;
int result = id > stuInfo.id ? 1 : (id == stuInfo.id ? 0 : -1);
return result;
}
public static void main(String[] args)
{
// 创建学生信息对象
StuInfo stu1 = new StuInfo(1, "kevinPan");
StuInfo stu2 = new StuInfo(2, "pan_junbiao");
StuInfo stu3 = new StuInfo(3, "pan_junbiao的博客");
// 创建HashSet集合对象,并添加集合元素
HashSet<StuInfo> stuHashSet = new HashSet<>();
stuHashSet.add(stu1);
stuHashSet.add(stu2);
stuHashSet.add(stu3);
// 遍历HashSet集合
System.out.println("HashSet集合中的所有元素(无序):");
for (StuInfo stu : stuHashSet)
{
System.out.println("编号:" + stu.getId() + " 姓名:" + stu.getName());
}
// 创建TreeSet集合对象,并添加集合元素
TreeSet<StuInfo> stuTreeSet = new TreeSet<StuInfo>();
stuTreeSet.add(stu1);
stuTreeSet.add(stu2);
stuTreeSet.add(stu3);
// 遍历TreeSet集合
System.out.println("\nTreeSet集合中的所有元素(有序):");
for (StuInfo stu : stuTreeSet)
{
System.out.println("编号:" + stu.getId() + " 姓名:" + stu.getName());
}
}
}
执行结果:
5、Map集合
Map集合没有继承Collection接口,其提供的是key到value的映射。Map中不能包含相同的key,每个key只能映射一个value。key还决定了存储对象在映射中的存储位置,但不是由key对象决定的,而是通过一种“散列技术”进行处理,产生一个散列码的整数值。散列码通常用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存放位置。Map集合包括Map接口以及Map接口的所有实现类。
5.1 Map接口
Map接口提供了将key映射到值的对象。一个映射不能包含重复的key,每个key最多只能映射到一个值。Map接口中同样提供了集合的常用方法,除此之外还包括如下表所示的常用方法。
Map接口中的常用方法:
方法 | 说明 |
---|---|
put(Object key,Object value) | 向集合中添加指定的key与value的映射关系。 |
containsKey(Object key) | 如果此映射包含指定key的映射关系,则返回true。 |
containsValue(Object value) | 如果此映射将一个或多个key映射到指定值,则返回true。 |
get(Object key) | 如果存在指定的key对象,则返回该对象对应的值,否则返回null。 |
keySet() | 返回该集合中所有key对象形成的Set集合。 |
values() | 返回该集合中所有值对象形成的Collection集合。 |
remove(Object key) | 删除由指定的键映射的“键-值对”。 |
示例:在项目中创建UpdateStu,在主方法中创建Map集合,并获取Map集合中所有key对象的集合和所有values值的集合,最有遍历集合。
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map集合的使用示例
*
* @author pan_junbiao
*
*/
public class UpdateStu
{
public static void main(String[] args)
{
// 创建Map实例
Map<String, String> map = new HashMap<>();
// 向集合中添加对象
map.put("001", "pan_junbiao");
map.put("002", "pan_junbiao的博客");
// 获取与遍历Map集合中所有key对象的集合
Set<String> set = map.keySet();
System.out.println("key集合中的元素:");
for (String key : set)
{
System.out.println(key);
}
// 获取与遍历Map集合中所有values值的集合
Collection<String> coll = map.values();
System.out.println("values集合中的元素:");
for (String value : coll)
{
System.out.println(value);
}
}
}
执行结果:
5.2 Map接口的实现类
Map接口常用的实现类有HashMap和TreeMap。建议使用HashMap类实现Map集合,因为由HashMap类实现的Map集合对于添加和删除映射关系效率更高。HashMap是基于哈希表的Map接口的实现,HashMap通过哈希码对其内部的映射关系进行快速查找;而TreeMap中的映射关系存在一定的顺序,如果希望Map集合中的对象也存在一定的顺序,应该使用TreeMap类实现Map集合。
HashMap类是基于哈希表的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性。 HashMap通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
TreeMap类不仅实现了Map接口,还实现了java.util.SortedMap接口,因此,集合中的映射关系具有一定的顺序。但在添加、删除和定位映射关系时,TreeMap类比HashMap类性能稍差。由于TreeMap类实现的Map集合中的映射关系是根据键对象按照一定顺序排列的,因此不允许键对象是null。
示例:通过HashMap类实例化Map集合,并遍历该Map集合,然后创建TreeMap实例实现将集合中的元素顺序输出。
(1)首先创建Emp类:
/**
* 员工信息类
*
* @author pan_junbiao
*
*/
public class Emp
{
private String e_id;
private String e_name;
public Emp(String e_id, String e_name)
{
this.e_id = e_id;
this.e_name = e_name;
}
public String getE_id()
{
return e_id;
}
public void setE_id(String e_id)
{
this.e_id = e_id;
}
public String getE_name()
{
return e_name;
}
public void setE_name(String e_name)
{
this.e_name = e_name;
}
}
(2)创建测试主类:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Map集合的使用示例
*
* @author pan_junbiao
*
*/
public class MapText
{
public static void main(String[] args)
{
// 由HashMap实现的Map对象
Map<String, String> map = new HashMap<>();
// 创建Emp对象
Emp emp1 = new Emp("351", "张三");
Emp emp2 = new Emp("512", "李四");
Emp emp3 = new Emp("853", "王一");
Emp emp4 = new Emp("125", "pan_junbiao");
Emp emp5 = new Emp("341", "pan_junbiao的博客");
// 将对象添加到集合中
map.put(emp1.getE_id(), emp1.getE_name());
map.put(emp2.getE_id(), emp2.getE_name());
map.put(emp3.getE_id(), emp3.getE_name());
map.put(emp4.getE_id(), emp4.getE_name());
map.put(emp5.getE_id(), emp5.getE_name());
Set<String> set = map.keySet(); // 获取Map集合中的key对象集合
Iterator<String> it = set.iterator();
System.out.println("HashMap类实现的Map集合,无序:");
while (it.hasNext())
{ // 遍历Map集合
String str = (String) it.next();
String name = (String) map.get(str);
System.out.println(str + " " + name);
}
TreeMap<String, String> treemap = new TreeMap<>(); // 创建TreeMap集合对象
treemap.putAll(map); // 向集合添加对象
Iterator<String> iter = treemap.keySet().iterator();
System.out.println("\nTreeMap类实现的Map集合,键对象升序:");
while (iter.hasNext())
{ // 遍历TreeMap集合对象
String str = (String) iter.next(); // 获取集合中的所有key对象
String name = (String) treemap.get(str); // 获取集合中的所有values值
System.out.println(str + " " + name);
}
}
}
执行结果:
6、总结:
(1)Collection是最基本的集合接口。List接口继承自Collection接口,List是有序集合,允许有相同的元素。Map提供键到值的映射。
(2)ArrayList是List接口的一个实现类,它实现了可变大小的数值,在进行随机访问和遍历元素时,它提供更好的性能。
(3)LinkedList是List接口的一个实现类,它提供了额外的addFirst()、addLast()、removeFirst()、removeLast()等方法,可以在LinkedList首部或者尾部进行插入或者删除操作。而且,相较于ArrayList类,在插入或者删除元素时,LinkedList提供更好的性能。
(4)HashMap是Map接口的实现类,实现一个键到值元素的哈希表。
7、ArrayList、LinkedList和Vector的区别
以下内容转载至博客园:Java中Vector和ArrayList的区别 - 昵称加载失败~ - 博客园
首先看这两类都实现List接口,而List接口一共有三个实现类,分别是ArrayList、LinkedList和Vector。List用于存放多个元素,能够维护元素的次序,并且允许元素的重复。3个具体实现类的相关区别如下:
(1)ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
(2)Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问Vector比访问ArrayList慢。
(3)LinkedList是用链表结构存储数据,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,它还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
(4)Vector是线程(Thread)同步(Synchronized)的,所以它也是线程安全的,而ArrayList是线程异步(ASynchronized)的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
(5)如果集合中的元素的数目大于目前集合数组的长度时,Vector增长率为目前数组长度的100%,而ArrayList增长率为目前数组长度的50%.如果在集合中使用数据量比较大的数据,用Vector有一定的优势。
(6)如果查找一个指定位置的数据,Vector和ArrayList使用的时间是相同的,都是0(1),这个时候使用Vector和ArrayList都可以。而如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用LinkedList,因为它移动一个指定位置的数据所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号检索元素,但是插入数据要涉及到数组元素移动等内存操作,所以检索数据快,插入数据慢,Vector由于使用了 synchronized 方式(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号检索数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快。
(7)笼统来说:ArrayList:查询快(有索引的存在);LinkedList:增删改快。