集合
- Collection接口:是集合层次中的一个根接口,Collection 表示一组对象,这些对象也称为 Collection 的元素。一些Collection 允许有重复的元素,而另一些则不允许。一些Collection 是有序的,而另一些则是无序的,JDK 不提供此接口的任何直接实现,Collection接口是List接口和Set接口的父接口。
- List接口:有序、可包含重复元素的Collection,通常被称为链表,此接口的用户可以对列表中每个元素的插入位置进行精确地控制,用户也可以根据元素的整数索引访问元素,并搜索链表中的元素。
- Set接口:无序、不包含重复元素的Collection,通常被称为集合。
- Map接口:组织映射数据,表示很多数据,每个数据都会包含两部分,一部分是数据,另一部分是键,每个数据称为键/值对(key/value)。
- Iterator接口:对Collection 进行迭代的迭代器接口。
一、Collection接口
Collection接口用来存放一组称为元素的对象,一个Collection中可以放不同类型的数据,它是Set接口和List接口的父接口。其中元素是否有特定的顺序以及是否允许重复,取决于它的实现类。
(1) 子接口Set:无序的集合,不允许重复。
Set接口的实现类:HashSet
(2) 子接口List:有序的集合,允许重复。
List接口的实现类:ArrayList、LinkedList
(1)、第一类方法,向集合中添加对象的方法
可以添加一个,也可以添加多个,添加多个也就是把另外一个集合的元素添加进来,下面的两个方法是添加对象的方法:
public boolean add(Object o):向集合中添加参数指定的元素。
public boolean addAll(Collection c) :向集合中添加参数指定的所有元素。
(2)、第二类方法,从集合中删除元素的方法
可以删除一个,可以删除多个,还可以删除所有的元素,此外还有一个特殊的,删除某些元素之外的所有元素,所以对应的方法也有四个:
public boolean remove(Object o) :删除指定的某个元素。
public boolean removeAll(Collection c) :删除指定的多个元素。
public void clear():删除所有的元素。
public boolean retainAll(Collection c) :只保留指定集合中存在的元素,其他的都删除,相当于取两个集合的交集。
(3)、第三类方法,判断集合中元素的方法
public boolean isEmpty():用于判断集合是否是空的。
public boolean contains(Object o) :判断是否包含指定的元素。
public boolean containsAll(Collection c) :判断是否包含指定的多个元素。
public int size():用于获取集合中元素的个数。
(4)、第四类方法,与其它类型的对象进行转换的方法
public Iterator iterator():转换成迭代器,方便集合中元素的遍历。
public Object[] toArray():返回一个包含所有元素的对象数组,也是方便集合中元素的遍历。
通常在管理集合的过程中,使用集合本身提供的方法,但是遍历集合最好先转换成迭代器或者数组,这样访问比较方便,并且效率比较高。
(5)、第五类方法,比较通用的方法
public boolean equals(Object o) :判断是否与另外一个对象相同。
public int hashCode():返回集合的哈希码。
二、List接口
(1)、第一类方法,在指定的位置上添加元素
public void add(int index , Object o):第一个参数表示要添加的元素的位置,从0开始。
public boolean addAll(int index , Collection c) :第一个参数表示位置,如果不指定位置,默认在最后添加。
(2)、第二类方法,删除指定位置的元素
public Object remove(int index) :参数用于指定要删除的元素的位置。
(3)、第三类方法,获取某个元素或者获取某些元素
public Object get(int index) :获取指定位置的元素。
public List subList(int fromIndex,int toIndex) :获取从fromIndex到toIndex这些元素,包括fromIndex,不包括toIndex。
(4)、第四类方法,查找某个元素
public int indexOf(Object o) :查找元素在集合中第一次出现的位置,并返回这个位置,如果返回值为-1,表示没有找到这个元素。
public int lastIndexOf(Object o) :查找元素在集合中最后一次出现的位置。
(5)、第五类方法,修改元素的方法
public Object set(int index , Object o) :用第二个参数指定的元素替换第一个参数指定位置上的元素。
(6)、第六类方法,转换成有顺序的迭代器:
public ListIterator listIterator():把所有元素都转换成有顺序的迭代器。
public ListIterator listIterator(int index) :从index开始的所有元素进行转换。
List与Set相比,主要是增加了元素之间的顺序关系,并且允许元素重复。List有三种主要的实现类:
- ArrayList
- LinkedList
- Vector
1 . ArrayList实现类
ArrayList是数据结构中数组的Java实现,ArrayList是一种动态数组,它是java.util包中的一个类。原则上所有的对象都可以加入到ArrayList里,但通常为了使用方便,一般可以通过泛型()限定加入到ArrayList中的元素类型以保证加入的都是相同类型的元素。
该类的构造方法有3种:
ArrayList():构造一个初始容量为10的空的链表;
ArrayList(Collection<? extends E> c):使用1个已经存在的集合构造一个链表,集合中的元素在新的链表中的顺序由集合的iterator()方法决定。
ArrayList(int initialCapacity) :构造一个由参数指定初始化空间大小的链表。
下面的代码分别展示了3种用法:
ArrayList list1 = new ArrayList();
list1.add("user1");
list1.add("user2");
ArrayList list2 = new ArrayList(list1);
ArrayList list3 = new ArrayList(8);
其中list2使用list1中的元素进行初始化。注意在使用ArrayList的时候应该是指定元素的类型。这里使用了泛型,泛型的使用我们将会在2.6中做详细介绍。
ArrayList其它的主要方法还包括:
(1)、向ArrayList中添加对象
可以在最后添加,也可以在指定的位置添加对象。可以添加一个,可以添加多个,添加多个也就是把另外一个集合的元素添加进来。
public void add(int index,Object o):第一个参数表示要添加的元素的位置,从0开始。
public boolean addAll(int index,Collection c) :第一个参数表示位置,如果不指定位置,默认在最后添加。
public boolean add(Object o) :在链表的最后添加参数指定的元素。
public boolean addAll(Collection c) :在链表最后添加参数指定的所有元素。
下面的代码展示了这些方法的应用:
list1.add("user3");
list1.addAll(list2);
list1.add(0,"user0");
运行后集合中的元素为:[user0, user1, user2, user3, user1, user2]
(2)、删除特定的元素
可以删除一个,可以删除多个,还可以删除所有的元素,此外还有一个特殊的,删除某些元素之外的所有元素,所以对应的方法也有四个:
public boolean remove(Object o):删除指定的某个元素。
public boolean removeAll(Collection c) :删除指定的多个元素。
public void clear():删除所有的元素。
public boolean retainAll(Collection c) :只保留指定集合中存在的元素,其他的都删除,相当于取两个集合的交集。
public Object remove(int index) :参数用于指定要删除的元素的位置。
下面的代码删除了user1:
list1.remove("user1");
注意:这里只删除了第一个出现的user1。
(3)、获取某个元素或者获取某些元素
可以获取某个位置的单个元素,也可以获取多个元素。
public Object get(int index):获取指定位置的元素。
public List subList(int fromIndex,int toIndex) :获取从fromIndex到toIndex这些元素,包括fromIndex,不包括toIndex。
要获取第三个元素可以使用下面的代码:
String str = list1.get(2);
结果是:user3
当前集合中的元素为:user0, user2, user3, user1, user2。
(4)、查找某个元素
可以根据位置查找集合中的对象,也可以判断结合中是有对象,以及是否是空的,元素的个数等。
public int indexOf(Object o):查找元素在集合中第一次出现的位置,并返回这个位置,如果返回值为-1,表示没有找到这个元素。
public int lastIndexOf(Object o) :查找元素在集合中最后一次出现的位置。
public boolean isEmpty():用于判断集合是否是空的。
public boolean contains(Object o) :判断是否包含指定的元素。
public boolean containsAll(Collection c) :判断是否包含指定的多个元素。
public int size(),用于获取集合中元素的个数。
下面的代码用于查找user1第一次出现和最后一次次出现的位置。
System.out.println(list1.indexOf("user2"));
System.out.println(list1.lastIndexOf("user2"));
得到的结果:
1
4
当前集合中的元素为:user0, user2, user3, user1, user2。
(5)、修改元素的方法
public Object set(int index,Object o):用第二个参数指定的元素替换第一个参数指定位置上的元素。
下面的代码把第二个元素修改user4:
list1.set(1,"user4");
集合中原来的元素:user0, user2, user3, user1, user2。
修改后的元素为:user0, user4, user3, user1, user2。
(6)、转换成其它对象
public ListIterator listIterator():把所有元素都转换成有顺序的迭代器。
public ListIterator listIterator(int index) :从index开始的所有元素进行转换。
public Iterator iterator():转换成迭代器,方便集合中元素的遍历。
public Object[] toArray():转换成数组,也是方便集合中元素的遍历。
(7)、ArrayList的遍历
可以采用下面的3种方法进行遍历。
方法1:
for(int i=0;i<list1.size();i++){
System.out.println(list1.get(i));
}
方法2:
Object o[] = list1.toArray();
for(int i=0;i<o.length;i++){
String temp = (String)o[i];
System.out.println(temp);
}
方法3:
Iterator i = list1.iterator();
while(i.hasNext()){
String temp = i.next();
System.out.println(temp);
}
通常在管理集合的过程中使用集合本身提供的方法,但是遍历集合最好先转换成迭代器或者数组,这样访问比较方便,并且效率比较高。
2.LinkedList实现类
LinkedList是数据结构中链表的Java实现,相对于ArrayList来说,LinkedList最主要的功能增强是可以在List的头部和尾部添加、删除、取得元素,直接提供了这些方法的实现。所以它可以非常方便的实现我们数据结构中的常见的Stack(栈)、queue(队列)等。LinkedList类的构造方法如下:
LinkedList 变量名 = new LinkedList() ;
LinkedList 变量名 = new LinkedList(Collection c) ;
方法 |
含义 |
void addFirst(Object o) |
将给定元素插入此列表的开头 |
void addLast(Object o) |
将给定元素追加到此列表的结尾 |
Object getFirst() |
返回此列表的第一个元素 |
Object getLast() |
返回此列表的最后一个元素 |
Object removeFirst() |
移除并返回此列表的第一个元素 |
Object removeLast() |
移除并返回此列表的最后一个元素 |
三、Iterator接口
3个方法的作用如下:
hasNext():判断迭代器中是否有下一个元素,如果有,返回true,否则返回false。
next():用于得到下一个元素,返回值是Object类型,需要强制转换成自己需要的类型。
remove():用于删除元素。
关于迭代器的使用,通常是在得到它之后,对它进行遍历。
ListIterator接口是Iterator接口的子接口,相对于Iterator,它提供了更多方法
四、for each循环
for-each循环是对for循环的增强,主要用来对集合类型对象的遍历,是JDK5.0之后才支持的,但是有一定的约束。
for-each循环的基本结构如下:
for (数据类型 变量名:数组名) 循环体语句
其中,变量的数据类型必须与数组的数据类型一致,变量按照从头到尾的顺序,每次迭代接收数组中的一个元素,循环不断重复,直到获得了数组中的所有元素为止。
循环体中的代码主要是对标识变量的操作。
如果使用I表示元素的类型,标识符变量使用i,表达式是exp,要执行的语句为statements,for-each循环的格式如下:
for (I i:exp){
statements;
}
五、Set接口及其实现类
Set接口是Collection接口的子接口,表示集合,对实现该接口的对象有个要求,就是集合中的元素不允许重复,该接口与Collection接口基本一致,方法与Collection完全相同。Set接口的实现类有两个:
- HashSet — HashSet的特性在于其内部对象的散列存取,即采用哈希技术。散列存储,又称hash存储,是一种力图将数据元素的存储位置与关键码之间建立确定对应关系的查找技术。散列法存储的基本思想是:由节点的关键码值决定节点的存储地址。散列技术除了可以用于查找外,还可以用于存储。
- TreeSet — TreeSet存入的顺序跟存储的顺序不同,但是存储是按照排序存储的。
下面分别来介绍下这两个实现类的用法。
1.HashSet类
HashSet是实现Set接口的一个类,具有以下的特点:
- 不能保证元素的排列顺序,顺序有可能发生变化。
- HashSet不是同步的,如果多个线程同时访问一个Set,只要有一个线程修改Set中的值,就必须进行同步处理,通常通过同步封装这个Set的对象来完成同步,如果不存在这样的对象,可以使用Collections.synchronizedSet()方法完成。
- Set s = Collections.synchronizedSet(new HashSet(...));
- 元素值可以是null。
主要方法如下:
(1)、构造方法
提供了4个构造方法:
public HashSet();
public HashSet(Collection<? extends E> c);
public HashSet(int initialCapacity);
public HashSet(int initialCapacity,float loadFactor);
第1个方法创建初始化大小为16,加载因子为0.75的默认实例,第2个方法是以已经存在的集合对象中的元素为基础创建新的HashSet实例,第3个方法根据指定的初始化空间大小的实例,第4个方法在创建实例的时候不仅指出了初始化大小空间,同时也指出了加载因子。
(2)添加元素的方法
可以添加一个,可以添加多个,添加多个也就是把另外一个集合的元素添加进来。下面的两个方法是添加元素的方法:
public boolean add(Object o):向集合中添加参数指定的元素。
public boolean addAll(Collection c) :向集合中添加参数指定的所有元素。
(3)删除元素的方法
可以删除一个,可以删除多个,还可以删除所有的元素,此外还有一个特殊的,删除某些元素之外的所有元素,所以对应的方法也有4个:
public boolean remove(Object o):删除指定的某个元素。
public boolean removeAll(Collection c) :删除指定的多个元素。
public void clear():删除所有的元素。
public boolean retainAll(Collection c) :只保留指定集合中存在的元素,其他的都删除,相当于取两个集合的交集。
(4)、查找元素的方法
HashSet提供了判断元素是否存在的方法,方法定义如下:
public boolean contains(Object o):如果包含则返回true,否则返回false。
(5)、判断集合是否为空
方法定义如下:
public boolean isEmpty( ):如果集合为空返回true,否则返回false。
(6)、遍历集合的方法
HashSet提供了两种遍历集合的方法:
public Iterator iterator():转换成迭代器,方便集合中元素的遍历。
public Object[] toArray():转换成数组,也是方便集合中元素的遍历。
通常在管理集合的过程中使用集合本身提供的方法,但是遍历集合最好先转换成迭代器或者数组,这样访问比较方便,并且效率比较高。
下面是对HashSet进行遍历的两种方式。
方式1:得到迭代器对象
Iterator i = set1.iterator();
while(i.hasNext()){
String temp = (String)i.next();
System.out.println(temp);
}
方式2:转换成数组
Object o[] = hs.toArray();
for(int i=0;i < o.length;i++){
System.out.println((String)o[i]);
}
2.TreeSet类
前面介绍的Set接口中的元素是没有顺序的,SortedSet继承了Set接口,但是SortedSet中的元素是按照升序排列的。排列的顺序既可以按照元素的自然顺序,也可以按照创建SortedSort时指定的Comparator对象。所有插入SortedSort中的元素必须实现Comparator,实现了该接口的类只有TreeSet类。
主要方法如下:
①一类方法,得到相关的Comparator对象:
- public Comparator comparator(),返回相关的comparator对象,如果按照自然排序,返回null。
②二类方法,获取子集的方法:
- public SortedSort subSet(Object fromElement,Object toElement),获取从fromElement到toElement的元素,包含fromElement,不包含toElement。
- public SortedSet headSet(Object toElement),获取从开头到toElement的所有元素,不包含toElement。
- public SortedSet tailSet(Object fromElement),获取从fromElement开始到结束的所有元素,包含fromElement。
③三类方法,获取元素的方法:
- public Object first(),获取第一个元素。
- public Object last(),获取最后一个元素。
六、Map接口及其实现类
Map接口同样是包含多个元素的集合,Map内存储的是“键/值对”这样以成对的对象组(可以把一组对象当成一个元素),通过“键”对象来查询“值”对象。Map是不同于Collection的另外一种集合接口。Map的每个元素包括两个部分:键(Key)和值(Value)。同一个Map对象中不允许使用相同的键,但是允许使用相同的值。所以Map接口隐含的有3个集合:键的集合、值的集合和映射的集合。
Map和List有一些相同之处,List中的元素是用位置确定的,元素虽然可以相同,但是位置不能相同,也就是不会出现某个位置两个元素的情况,而Map中的元素是通过键来确定的,如果把List中的位置信息看成键的话,List也可以是一种特殊的Map。
与Collection接口相比,Map接口中主要增加了通过键进行操作的方法,就像List中增加了通过位置进行操作的方法一样。
①**一类方法,添加元素的方法:**
§ public Object put(Object key,Object value),第一个参数指定键,第二个参数指定值,如果键存在,则用新值覆盖原来的值,如果不存在添加该元素。
§ public void putAll(Map m),添加所有参数指定的映射。
②**二类方法,获取元素的方法:**
§ public Object get(Object key),获取指定键所对应的值,如果不存在,返回null。
③**三类方法,删除元素的方法:**
§ public Object remove(Object key),根据指定的键删除元素,如果不存在该元素,返回null。
④**四类方法,与键集合、值集合和映射集合相关的操作:**
§ public Set entrySet(),获取映射的集合。
§ public Collection values(),获取值的集合。
§ public Set keySet(),返回所有键名的集合。
这3个方法的返回值不一样,因为Map中的值是允许重复的,而键是不允许重复的,当然映射也不会重复。Set不允许重复,而Collection允许重复。
⑤**五类方法,判断是否存在指定Key和Value的方法:**
§ public boolean containsValue(Object value),判断是否存在值为value的映射。
§ public boolean containsKey(Ojbect key),判断是否存在键为key的映射。
Map接口有三个实现:
§ Hashtable — 主要用于存储一些映射关系。
§ HashMap — key/value对是按照Hash算法存储的。
§ TreeMap — key/value对是排序(按key排序)存储的。
1.Hashtable**类**
实现了Map接口,是同步的哈希表,不允许类型为null的键名和键值。哈希表主要用于存储一些映射关系。这个类比较特殊,与Collection中的其他类不太一样,首先它是同步的,另外它是继承自java.util.Dictionary类。
一个典型的应用就是在连接数据库的时候,需要提供各种参数,包括主机、端口、数据库ID、用户名、口令等,可以把这些信息先存储在哈希表中,然后作为参数使用。
2.HashMap**类**
是基于Hash表的Map接口实现。该类提供了所有的可选的映射操作,允许null值和null键。HashMap类和Hashtable基本相同,只是HashMap不同步,并且允许null键和null值。这个类不能保证元素的顺序,特别是顺序有可能随着时间变化。
HashMap使用了泛型,泛型的具体内容将会在2.6节讲解,读者可参看2.6节阅读本例。对于Map类型的集合,在定义对象的时候同时要指定Key的类型和Value的类型。
HashMap对象的遍历。假设map是HashMap的对象,对map进行遍历可以使用下面两种方式:
第一种:得到元素的集合,然后进行运算,元素类型是Map.Entry。
//得到元素集合,然后转换成数组
Object[] o = map.entrySet().toArray();
Map.Entry x ;
// 对数组进行遍历
for(int i=0; i < map.size(); i++){
// 取出数组的每一个元素
x = (Map.Entry)o[i];
// 获取该元素的key
Object key = x.getKey();
//获取该元素的值
Object value = x.getValue();
}
第二种:先得到所有元素的Key的集合,然后根据key得到每个key对应的value。
//先得到key的集合,然后转换成数组
Object[] o = map.keySet().toArray();
//对数组进行遍历
for(int i=0; i < o.length; i++){
//根据key得到具体的value。
Object value = map.get(o[i]);
}
3.HashMap**与TreeMap的比较**
HashMap与TreeMap区别如下:
§ HashMap基于哈希表实现。
§ TreeMap基于树实现。
§ HashMap可以通过调优初始容量和负载因子,优化HashMap空间的使用。
§ TreeMap没有调优选项,因为该树总处于平衡状态
§ HashMap性能优于TreeMap。
4.HashMap与HashTable的比较
HashMap与HashTable区别如下:
§ Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。
§ Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。
§ HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
5.如何选择集合类
实际应用中,集合类的选择主要依据如下:
- Set内存放的元素不允许重复,List存放的元素有一定的顺序。
- Map的应用主要在利用键/值对进行快速查询。
- ArrayList和LinkedList的区别在于随机查询性能上ArrayList要好,但LinkedList的中间元素的插入与删除性能好。
- HashSet和TreeSet的区别在于集合内元素是否排序。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix