Collection接口【集合】**
一、概述
集合到底是什么呢 ?
- 集合是java中提供的一种容器,可以用来存储多个数据。
集合和数组既然都是容器,它们有啥区别呢 ?
- 数组的长度是固定的。集合的长度是可变的。
- int[ ] arr = new int[10];
- Student[ ] arr = new Student[3];
- ArrayList//
- 数组中存储的是同一类型的元素,可以存储基本数据类型值。
- 集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。
二、集合框架
集合按照其存储结构可以分为两大类,分别是单列集合java.util.collection 和 双列集合java.util.Map
Collection,单列集合类的根接口,用于存储一系列符合某种规则的元素。它有两个重要的子接口
分别是 java.util.List 和 java.util.Set 。
其中,List的特点是元素有序、元素可重复。Set 的特点是元素无序,而且不可重复。
List接口的主要实现类有 java.util.ArrayList 和 java.util.LinkedList。
Set 接口的主要实现类有 java.util.Hashset 和 java.util.TreeSet。
通过一张图来描述整个集合类的继承体系。
三、Collection集合常用方法
boolean add(E e)//向集合中添加元素
boolean remove(E e)//删除集合中的某个元素
void clear()//清空集合所有的元素
boolean contains(E e)//判断集合中是否包含某个元素
boolean isEmpty0)//判断集合是否为空
int size()//获取集合的长度
object[] toArray()//将集合转成一个数组
Iterator<E> iterator() //返回在此 collection 的元素上进行迭代的迭代器。
四、迭代器
在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口
java.util.Iterator 。Iterator接口也是Java集合中的一员,但它与collection 、Map接口有所不同,Collection接口与Map 接口主要用于存储元素,而 Iterator主要用于迭代访问(即遍历) collection 中的元素,因此 Iterator对象也被称为迭代器。想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作。
获取迭代器的方法∶
-
public Iterator iterator( ) : 获取集合对应的迭代器,用来遍历集合中的元素的。
-
迭代的概念︰
- 迭代 : 即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
lterator接口的常用方法如下︰
public E next()//返回迭代的下一个元素。
public boolean hasNext()//如果仍有元素可以迭代,则返回true。
例子:
public class IteratorTest {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("李白");
arrayList.add("王昭君");
arrayList.add("韩信");
arrayList.add("刘邦");
// foreach 输出
for (String s : arrayList) {
System.out.println(s);
}
//迭代器 输出
Iterator<String> iterator = arrayList.iterator();//获取一个迭代器
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
五、增强 for 循环
增强for循环 (也称for each循环) 是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。
格式︰
for (元素的数据类型变量 : collection集合 or 数组 ){
//写操作代码
}
它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。
六、List 接口
一、概述
- List 接口介绍
java.util.List 接口继承自collection接口,是单列集合的一个重要分支,习惯性地会将实现了List 接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。 - List接口特点∶
- 它是一个元素存取有序的集合。
- 例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)
- 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
- 它是一个元素存取有序的集合。
二、常用方法
/*list接口中带索引的方法(特有)*/
//将指定的元素,添加到该集合中的指定位置上。
public void add(int index, E element)
//返回集合中指定位置的元素。
public E get( int index)
//移除列表中指定位置的元素,返回的是被移除的元素。
public E remove(int index)
//用指定元素替换集合中指定位器的元素,返回值的更新前的元素
public E set(int index,E eLement)
三、ArrayList
java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。
许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。
四、LinkedList集合
java.util.LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。LinkedList是一个双向链表,那么双向链表是什么样子的呢,我们用个图了解下。
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方法我们作为了解即可:
public void addFirst(E e)//将指定元素插入此列表的开头。
public void addLast(E e)//将指定元素添加到此列表的结尾。
public E getFirst()//返回此列表的第一个元素。
public E getLast()//返回此列表的最后一个元素。
public E removeFirst()//移除并返回此列表的第一个元素。
public E removeLast()]//移除并返回此列表的最后一个元素。
public E pop()//从此列表所表示的堆栈处弹出一个元素。
public void push(E e)//将元素推入此列表所表示的堆栈。
public boolean isEmpty()//如果列表不包含元素,则返回true。
LinkedList 是 List的子类,List 中的方法 LinkedList 都是可以使用,这里就不做详细介绍,我们只需要了解LinkedList的特有方法即可。在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。(了解即可)
七、Set 接口
一、概述
java.util.Set 接口和java.util.List 接口一样,同样继承自 collection 接口,它与 collection 接口中的方法基本一致,并没有对collection接口进行功能上的扩充,只是比 collection接口更加严格了。与List 接口不同的是,set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
set集合有多个子类,这里我们介绍其中的java.util.HashSet、java.util.LinkedHashSet 这两个集合。
tips: Set 集合取出元素的方式可以采用 : 迭代器、增强for。
简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示 :
元素不会重复的原理:
二、 HashSet集合介绍
1、HashSet
java.util.HashSet是 set 接口 的 一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。java.util.HashSet 底层的实现其实是一个 java.util.HashMap 支持,由于我们暂时还未学习,先做了解。
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于: hashcode 与 equals方法。
2 HashSet集合存储数据的结构(哈希表)
什么是哈希表呢?
在 JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。
而 JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的。
哈希值 :是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址),在object类有一个方法, 可以获取对象的哈希值 int hashcode( ) 返回 该对象的哈希码值。
hashcode方法的源码 :
public native int hashcode();//native:代表该方法调用的是本地操作系统的方法
3 、HashSet存储自定义类型元素
给HashSet中存放自定义类型元素时,需要重写对象中的 hashCode( ) 和 equals( ) 方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。
三、LinkedHashSet
我们知道 HashSet 保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?在HashSet下面有一个子类 java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。
// 例子
public class LinkedHashsetDemo {
public static void main(string[] args) {
Set<String> set = new LinkedHashset<String>();
set.add( "bbb");
set.add( "aaa" );
set.add( "abc");
set.add( "bbc" );
Iterator<String> it = set.iterator( );
while (it.hasNext()){
system.out.println(it.next());
}
}
}
/*
结果∶
bbb
aaa
abc
*/
五、Collections --集合工具类
常用功能
java.utils.collections 是集合工具类,用来对集合进行操作。
部分方法如下︰
//往集合中添加一些元素。
public static <T> boolean addAll(Collection<T> c,T... elements)
//打乱集合顺序[随机排序]
public static void shuffle(List<? > list)
//将集合中元素按照默认规则排序。
public static <T> void sort(List<T> list)
//将集合中元素按照指定规则排序。
public static T> void sort(List<T> list , comparator<? super T〉)
六、Map集合
一、概述
现实生活中,我们常会看到这样的一种集合∶IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。
Java提供了专门的集合类用来存放这种对象关系的对象,即 java.util.Map 接口。
我们通过查看Map接口描述,发现 Map接口下的集合与collection接口下的集合,它们存储数据的形式不同,如下图。
- collection 中的集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储。
- Map 中的集合,元素是成对存在的。每个元素由键与值两部分组成,通过键可以找对所对应的值。
- collection 中的集合称为单列集合,Map 中的集合称为双列集合。
- 需要注意的是,Map中的集合不能包含重复的键,值可以重复 :每个键只能对应一个值。
二、常用子类
通过查看Map接口描述,看到Map有多个子类,这里我们主要讲解常用的HashMap集合、LinkedHashMap集合。
- HashMap<K,V>∶存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
- LinkedHashMap<K,V> : HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致; 通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
- tips : Map接口中的集合都有两个泛型变量<K.V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。
三、常用方法
public Void put(K key,v value)//把指定的键与指定的值添加到Map集合中。
/*返回值:v
存储键值对的时候,key不重复,返回值v是null
存储键值对的时候,key重复,会使用新的value替换map中重复的value,返回被替换的value值 */
public Void remove(object key)//把指定的键所对应的键值对元素在Map集合中删除.
/*返回值: v
key存在, v返回被删除的值, key不存在,v返回null */
public Void get(0bject key)//根据指定的键,在Map集合中获取对应的值。
public Set<K> keySet()//获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,v>> entrySet()//获取到 Map集合中所有的键值对对象的集合(Set集合)。
package com.lly.myMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @ClassName:Maptest1
* @创建者: LLY
* @创建时间: 2021/4/24 22:24
* @version: 1.0
* @描述: Map 集合取值练习
* * Map集合遍历的第一种方式:
* 使用public Set<K> keySet()//获取Map集合中所有的键,存储到Set集合中。
*/
public class Maptest1 {
public static void main(String[] args) {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖", 165);
map.put("林志玲",178);
Set<String> keys = map.keySet();
// 使用增强for输出
for (String key : keys) {
System.out.println(key+"-->"+map.get(key));
}
System.out.println("=====================");
//使用迭代器输出
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next+"-->"+map.get(next));
}
}
}
四、public Set keySet( ) 方式取值
五、Entry键值对 对象 取值
我们已经知道,Map中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在wap中是
一对应关系,这一对对象又称做Map 中的一个Entry(项)。Entry)将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历wap集合时,就可以从每一个键值对([Entry )对象中获取对应的键与对应的值。
既然Entry表示了一对键和值,那么也同样提供了获取对应键和对应值得方法︰
public K getKey()//获取Entry对象中的键。
public v getValue()//获取Entry对象中的值。
在Map集合中也提供了获取所有 Entry对象 的方法∶
public Set<Map.Entry<K,v>> entrySet()//获取到Map集合中所有的键值对对象的集合(Set集合)。
六、Map集合遍历键值对方式
键值对方式︰即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。
操作步骤与图解︰
- 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示: entrySet() 。
- 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
- 通过键值对(Entry)对象,获取Entry对象中的键与值 。方法提示: getkey() getvalue()
package com.lly.myMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @ClassName:Maptest
* @创建者: LLY
* @创建时间: 2021/4/24 22:13
* @version: 1.0
* @描述: Map 集合取值练习
* ----------------------------------
* Map集合遍历的第二种方式:使用Entry对象遍历
* Map集合中的方法:
* set<Map.Entry<K,v>> entrySet()返回此映射中包含的映射关系的set视图。
* 实现步骤:
* 1.使用Map集合中的方法entrySet( ) ,把Map集合中多个Entry对象取出来,存储到一个set集合中
* 2.遍历set集合,获取每一个Entry对象
* 3.使用Entry对象中的方法getKey ()和 getValue(获取键与值
*/
public class Maptest {
public static void main(String[] args) {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖", 165);
map.put("林志玲",178);
Set<Map.Entry<String, Integer>> entries = map.entrySet();
// 使用增强for输出
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
System.out.println("=====================");
//使用迭代器输出
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> next = iterator.next();
String key = next.getKey();
Integer value = next.getValue();
System.out.println(key+"-->"+value);
}
}
}
七、存储自定义类型的变量
HashMap存储自定义类型键值Map集合保证key是唯一的 。
即: 作为key的元素,必须重写hashcode方法和equals方法,以保证key唯一。
八、 LinkedHashMap
我们知道HashMap保证成对元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,那么我们要保证有序,还要速度快怎么办呢?
在HashMap下面有一个子类LinkedHashMap,它是 链表和哈希表 组合 的一个数据存储结构。
九、Hashtable
java.util.Hashtable<K,V>集合 implements Map<K,V>接口
Hashtable : 底层也是一个哈希表,是一个线程安全的集合,是单线程集合 , 速度慢
HashMap : 底层是一个哈希表,是一个线程不安全的集合,是多线程的集合, 速度快HashMap集合
- (之前学的所有的集合) : 可以存储null 值, null 键。
- HashtabLe集合,不能存储 null值, null键。
Hashtable和vector集合一样,在 jd k1.2版本之后被更先进的集合(HashMap , ArrayList)取代了
Hashtable的子类 Properties 依然活跃在历史舞台 , Properties集合是一个唯—和Io流相结合的集合
十、补充知识点
-
JDK9对集合添加的优化
-
通常,我们在代码中创建一个集合(例如,List或Set ),并直接用一些元素填充它。实例化集合,几个add方法调用,使得代码重复。
-
public class Demo01 { public static void main( String[] args) { List<String> list = new ArrayList<>(); list.add( "abc" ); list.add("def" ); list.add("ghi"); system.out.println(list); } }
-
JDK9 的新特性 :
- list接口 , set接口 , Map接口 : 里边增加了一个静态的方法 of , 可以给集合一次性添加多个元素
-
static List of (E… elements)
-
使用前提:
- 当集合中存储的元素的个数已经确定了,不在改变时使用
-
注意:
- of方法只适用于List接口, set接口,Map接口,不适用于接口的实现类
- of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常.
- Set接口 和 Map接口 在调用 of方法 的时候,不能有重复的元素,否则会抛出异常
-
public static void main(String[] args) { List<string> list = List.of( "a","b", "a","c","d"'); System.out.println( list );//[a, b, a, c, d] //list.add( "w"); //UnsupportedoperationException:不支持操作异常 //Set<String〉 set = Set.of("a" " "b", " a",“c" “"d"); //TLlegaLArgumentException :非法参数异常,有重复的元素 set<string> set = set.of( "a","b","c", "d"); system.out.println(set); //set.add ( "w" ) ; // UnsuppertedoperationException:不支持操作异常 //Map<String,Integen〉 map = Map.of("张三",18,“李四",19,“王五",20,"张三",19);/ll/ILlegaLArgumentExcepti Map<String,Integer> map = Map.of(k1:"张三",18,"李四",19,"王五", 20); system.out.printin(map);//i王五=20,李四=19,张三=18} map.put("赵四", 30); //Unsupported0perationException:不支持操作异常 }
-