文章目录
第七章 集合
集合概念
存储一个班学员信息,假定一个班容纳20名学员 当我们需要保存一组一样(类型相同)的元素的时候,我们应该使用一个容器 来存储,数组就是这样一个容器。
数组的缺点:数组一旦定义,长度将不能再变化。 然而在我们的开发实践中,经常需要保存一些变长的数据集合,于是,我们需 要一些能够动态增长长度的容器来保存我们的数据。 而我们需要对数据的保存的逻辑可能各种各样,于是就有了各种各样的数据结构。
Java中对于各种数据结构的实现,就是我们用到的集合。
概念:Java集合是使程序能够存储和操纵元素不固定的一组数据。 所有Java集合类都位于java.uti包中。 与Java数组不同,Java集合中不能存放基本数据类型,只能存放对象的引用。
集合API
集合体系概述
Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中。
Collection接口
Collection 接口-定义了存取一组对象的方法,其子接口Set和List分别定义
了存储方式。
Set 中的数据对象没有顺序且不可以重复。
List 中的数据对象有顺序且可以重复。
在Collection 中定义了一些集合中的共有方法:
boolean add(Object element); //将元素添加到集合中
boolean remove(Object element); //删除指定元素,成功返回true,失败返回false;
void clear(); //将集合中的元素清空
int size(); //返回集合中的元素个数
boolean isEmpty(); //判断集合是否为空,为空返回true,不为空返回false;
boolean contains(Object element); //如果集合包含指定元素,则返回true,否则返回false;
boolean retainAll(Collection c);求交集,集合数据发生变化返回true, 不变返回false。
List 接口及实现类
List继承了Collection接口,有三个实现的类 (可重复)
- ArrayList
数组列表,数据采用数组方式存储,在内存中分配连续的空间。 添加慢,查询快, 中间增删慢(后面的元素位置要发生改变),所以遍历元素和随机访问元素的效率比较高
ArrayList的常用方法
add(int index, E element) //将元素添加到指定位置
get(int index) //获取指定位置的元素
indexOf(Object o) //返回给定元素第一次出现的索引,如果集合没有此元素,则返回-1;
lastIndexOf(Object o) //返回给定元素最后一次出现的索引,如果集合没有此元素,则返回-1;
remove(int index) //删除并返回指定位置元素
removeRange(int fromIndex, int toIndex)// 删除指定区间的元素(子类继承使用)
set(int index, E element)//用指定元素替换索引所在位置的元素
public class ArrayListDemo {
public static void main(String[] args){
ArrayList<String> str=new ArrayList<>();
str.add("f");
str.add("q");
str.add("w");
str.add("z");
str.add("x");
str.add("j");
str.add("n");
str.add(4, "v");//向指定位置添加元素
System.out.println(str);
System.out.println(str.get(4));//取出指定位置元素
System.out.println(str.remove(5));//删除并返回指定位置的元素
System.out.println(str);
str.set(3,"e");//替换指定位置的元素
System.out.println(str);
}
}
扩容方式:首先调用grow方法,会自动创建一个大小为10的数组,如果元素达到10个,还有元素需要存,那么该方法自动调用grow方法,会创建一个大小为以前数组的1.5倍的数组用于存储元素,下面就是源码扩容:
-LinkedList
以链表的方式进行存储,添加快,查询慢(必须从头/尾开始查找,直到找到),中间增删快,只需要改变后继节点位置。
LinkedList的常用方法
add(int index,Object element) //向指定位置添加元素
addFirist(Object element) //向集合的首位添加元素
addLast(Object element) //向集合的末尾添加元素
addLast(Object element)
get(int index) //获取指定索引的元素
removeFirst()//删除集合首位元素
removeLast() //删除集合末尾元素
remove(int index) //删除指定索引的元素
getFirst() //获取集合首位元素
getLast()//获取集合末尾元素
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
System.out.println(list);
System.out.println(list.get(3));//从指定位置获取元素
list.addFirst("X");//往首位添加元素
list.addLast("Y");//往末尾添加元素
System.out.println(list.removeFirst());//删除第一个元素并返回
System.out.println(list.removeLast());//删除最后一个元素并返回
System.out.println(list);
}
}
扩容方式:因为LinkedList是以链表的形式存储,所以在内存中就不用创建连续地址空间,因为链表会自动寻找空间,所以扩容方式没有ArrayList那么复杂。
-Vector
数组列表,添加同步锁,线程安全的
public class VectorDemo {
/*
用于线程安全,底层实现和ArrayList没区别
*/
public static void main(String[] args) {
Vector<String> v=new Vector<>();
v.add("a");
v.add("b");
v.add("c");
v.add("d");
v.add("e");
System.out.println(v);
}
}
List接口集合迭代
for循环遍历 (因为去重就需要遍历,所以这里就用该方式演示)
public class Demo2 {
/*
定义一个String类型的ArrayList集合,去除ArrayList中的重复元素
*/
public static void main(String[] args) {
ArrayList<String> str=new ArrayList<>();
str.add("a");
str.add("b");
str.add("c");
str.add("d");
str.add("d");
str.add("d");
str.add("d");
for (int i = 0; i < str.size(); i++) {
for (int j = i+1; j < str.size(); j++) {
if(str.get(i)== str.get(j)){
str.remove(j);
j--;
}
}
}
System.out.println(str);
}
}
增强for循环的遍历
import java.util.ArrayList;
public class Demo3 {
/*
定义一个String类型的ArrayList集合,去除ArrayList中的重复元素
*/
public static void main(String[] args) {
ArrayList<String> str=new ArrayList<>();
str.add("a");
str.add("b");
str.add("c");
str.add("d");
str.add("d");
str.add("d");
str.add("d");
for(String s:str){
System.out.println(s);
}
}
}
迭代器遍历(Iterator)
package com.ffyc.gather.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class IteratorDemo1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("d");
list.add("d");
list.add("d");
list.add("d");
list.add("e");
Iterator<String> it = list.iterator();
while (it.hasNext()) {//判断是否还有下一个元素
String str = it.next();
// System.out.println(str);遍历
if (str.equals("d")) {
it.remove();
}//删除重复项
}
System.out.println(list);
LinkedList<String> list1 = new LinkedList<>();
list1.add("a");
list1.add("b");
list1.add("c");
list1.add("d");
list1.add("d");
list1.add("d");
list1.add("d");
list1.add("d");
list1.add("f");
ListIterator<String> it1 = list1.listIterator();//第二种迭代器从指定位置开始遍历,这里从size()即末尾往前遍历
/*
ListIterator<String> it1 = list1.listIterator(list1.size());
while (it1.hasPrevious()) {
String str1 = it1.previous();
System.out.println(str1);
}
}
*/
while (it1.hasNext()) {//这里是从头开始遍历
String str1 = it1.next();
System.out.println(str1);
}
}
}
Set 接口
Set接口继承了Collection接口。
Set中所存储的元素是不重复的,但是是无序的, Set中的元素是没有索引的
Set接口有两个实现类
HashSet
HashSet类中的元素无序且不能重复,即彼此调用equals方法比较,都返回false。
底层数据结构是哈希表+链表
哈希表依赖于哈希值存储
package com.ffyc.gather.set;
public class Car implements Comparable<Car>{
private int no;
private String name;
public Car(int no, String name) {
super();
this.no = no;
this.name = name;
}
@Override
public int compareTo(Car o) {
return this.no-o.no;
}
@Override
public String toString() {
return "Car [no=" + no + ", name=" + name + "]";
}
}
package com.ffyc.gather.set;
import java.util.HashSet;
public class HashSetDemo1 {
public static void main(String[] args) {
/*
HashSet中不能存储重复元素
如何判断元素是否重复
在add的底层方法中,每天加一个元素时,就会判断集合中是否已经包含了此元素.
在底层使用hashCode()和equals()方法来判断内容是否重复
hashCode()是Object类中的方法
public native int hashCode(); native修饰的方法称为本地方法,java没有实现,是调用的操作系统中的方法
Object类中的 hashCode()获取的对象在内存中的地址
其他类中重写的hashCode(),都不对象的地址,而是根据对象内容计算出来的哈希值.
aaaaa-->int 1234
abcd-->int 1234
equals(); 除了Object类中的equals是比较对象地址,其他类中都是比较内容是否相等,因为equls效率很低
hashCode(); 判断时,先调用hashCode()计算哈希值,用整数哈希值来比较是否相等,这样提高了比较效率
但是此种做法不安全,因为内容不同,可能计算的哈希值相同.
equals(); 当有哈希值相同时,再去调用equal()方法比较内容是否相等. 这样就包证了安全性.
*/
//如果类中Car中没有重写hashCode(),调用的是Object中,默认是对象地址,每个new出来的对象都是独一无二的
Car s1 = new Car(101, "宝马");
Car s2 = new Car(102, "奔驰");
Car s3 = new Car(103, "大众");
Car s4 = new Car(101, "宝马");
HashSet<Car> set = new HashSet<>();
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
System.out.println(set);
}
}
TreeSet
可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。
TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)
package com.ffyc.gather.set;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
/*
有序且不重复
public TreeSet() {
this(new TreeMap<E,Object>());
TreeSet (键,值)键不可重复,值可以重复
如果键重复,只会保留最后一次,而且最后一次的值会覆盖前面的键所对应的值
}
*/
TreeSet<String> set = new TreeSet<>();
set.add("c");
set.add("b");
set.add("z");
set.add("a");
set.add("x");
set.add("x");
System.out.println(set);
Car car1 = new Car(1,"baoma1");
Car car2 = new Car(2,"baoma2");
Car car3 = new Car(3,"baom3");
TreeSet<Car> carset = new TreeSet<>();
carset.add(car1);
carset.add(car3);
carset.add(car2);
System.out.println(carset);//会以键排序
}
}
Set 接口集合迭代
遍历方式
增强for循环
package com.ffyc.gather.set;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
/*
有序且不重复
public TreeSet() {
this(new TreeMap<E,Object>());
TreeSet (键,值)键不可重复,值可以重复
如果键重复,只会保留最后一次,而且最后一次的值会覆盖前面的键所对应的值
}
*/
TreeSet<String> set = new TreeSet<>();
set.add("c");
set.add("b");
set.add("z");
set.add("a");
set.add("x");
set.add("x");
for(String s:set){
System.out.println(s);
}
}
}
迭代器遍历
package com.ffyc.gather.set;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
/*
有序且不重复
public TreeSet() {
this(new TreeMap<E,Object>());
TreeSet (键,值)键不可重复,值可以重复
如果键重复,只会保留最后一次,而且最后一次的值会覆盖前面的键所对应的值
}
*/
TreeSet<String> set = new TreeSet<>();
set.add("c");
set.add("b");
set.add("z");
set.add("a");
set.add("x");
set.add("x");
Iterator<String> it=set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
Map 接口
Map接口概述
将键映射到值的对象 ,一个映射不能包含重复的键 ,每个键最多只能映射到一个值。
Mapa接口常用方法
V put(K key,V value) //将给定的键,值存储到图中
V remove(Object key) //将图中指定键删除
void clear() //将图中所有的键和值删除
boolean containsKey(Object key) //如果图中含有指定键,则返回true
boolean containsValue(Object value) //如果图中含有指定值,则返回true
boolean isEmpty() //判断图中是否为空
int size() //返回图的大小
V get(Object key) //返回指定键的值
Collection values() 将键的值取出来放到定义的图中
Set keySet()//将键取出来放到定义的set中
Set<Map.Entry<K,V>> entrySet()//将键值对取出放到set中,这是一个内部类,遍历添加到set中
HashMap
HashMap中元素的key值不能重复,排列顺序是不固定的,可以存储一个为null的键。
1)TreeMap
TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序
的Map就应该使用TreeMap,key值所在类必须实现Comparable接口。
package com.ffyc.gather.map;
import java.util.Hashtable;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
/*
TreeMap
此实现提供了所有可选的地图操作,并不允许null的值和null键
*/
TreeMap<String,String> map = new TreeMap<>();
map.put("a", "aa");
map.put("s", "ss");
map.put("b", "bb");
map.put("x", "xx");
map.put("x", "aa");
map.get("b");
System.out.println(map);
Car car1 = new Car(1,"baoma1");
Car car2 = new Car(2,"baoma2");
Car car3 = new Car(3,"baom3");
TreeMap<Car,String> cmap = new TreeMap<>();
cmap.put(car1, "aaa");
cmap.put(car3, "ccc");
cmap.put(car2, "bbb");
System.out.println(cmap);
}
}
2)TreeMap
适用于按自然顺序或自定义顺序遍历键(key)。
TreeMap根据key值排序,key值需要实现Comparable接口,重compareTo方法。TreeMap根据compareTo的逻辑,对 key进行排序。
键是红黑树结构,可以保证键的排序和唯一性
package com.ffyc.gather.map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
/*
HashMap
此实现提供了所有可选的地图操作,并允许null的值和null键
*/
HashMap<String,String> map = new HashMap<>();
map.put("a", "aa");
map.put("s", "ss");
map.put("b", "bb");
map.put("x", "xx");
map.put("x", "aa");
map.put(null, "cc");
System.out.println(map.remove("a"));//删除主键为a的元素,并返回该键的值
//map.clear(); 删除全部元素
System.out.println(map.containsKey("a"));//如果此map包含指定键的映射,则返回 true
System.out.println(map.containsValue("aa"));//如果此map将一个或多个键映射到指定值,则返回 true
System.out.println(map.isEmpty());//是否为空
System.out.println(map.size());
Collection<String> c = map.values();//将键的值取出来放到定义的c中
Set<String> set = map.keySet();//将键取出来放到定义的set中
System.out.println(map.get("b"));
map.replace("b", "XXXX");
System.out.println(map);
System.out.println(c);
System.out.println(set);
}
}
Map集合遍历
方式1:根据键找值
1)获取所有键的集合
2)遍历键的集合,获取到每一个键
3)根据键找值
方式2:根据键值对对象找键和值
1)获取所有键值对对象的集合
2)遍历键值对对象的集合,获取到每一个键值对对象
3)根据键值对对象找键和值
package com.ffyc.gather.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class EntryDemo {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("111", "aaa");
map.put("222", "bbb");
map.put("444", "xxx");
map.put("333", "qqq");
map.put("666", "aaa");
Set<Map.Entry<String, String>> mapentry = map.entrySet();
/*双列表遍历,采用entry()方法,将Map转换为set,可以采用增强for循环遍历
增强for循环
//for(数据类型 变量名 : 需要循环的数据){
循环体
}
*/
// (数据类型 变量名 : 需要循环的数据)
for(Map.Entry<String,String> mapentry1 : mapentry){
System.out.println(mapentry1);
}
}
}
HashTable
实现了同步。
不能存储为null的键
Collections类
Collections是集合类的工具类,与数组的工具类Arrays类似。
addAl l(Col lection<? super T> c, T... elements); //向指定集合添加元素 binarySearch(List<? extends Comparable<? super T>> l ist, T key) 返回指定元素在集合的位置 sort(List l ist)对集合中的元素进行排序 sort(List l ist, Comparator<? super T> c)这是对Collections.sort方法重写,可以自定义排序,也是内部类,后边会学习 swap(List<?> l ist, int i, int j)//对集合指定两个位置进行交换
copy(List<? super T> dest, List<? extends T> src) ;//对集合进行复制,注意新的集合空间必须大于等于旧的集合空间 emptyList() 返回为空的集合,不能添加数据 fill(List<? super T> l ist, T obj)//用指定的元素代替指定列表的所有元素。 max(Col lection<? extends T> col l)//根据其元素的 自然顺序返回给定集合的最大元素。 min(Col lection<? extends T> col l)//根据其元素的 自然顺序返回给定集合的最小元素。 replaceAl l(List l ist, T oldVal, T newVal)//将集合中某个值全部替换为指定值 reverse(List<?> l ist)//反转指定列表中元素的顺序。
shuffle(List<?> l ist) //使用默认的随机源随机排列指定的列表。 lection<? super T> c, T... elements); //向指定集合添加元素 binarySearch(List<? extends Comparable<? super T>> l ist, T key) 返回指定元素在集合的位置 sort(List l ist)对集合中的元素进行排序 sort(List l ist, Comparator<? super T> c)这是对Collections.sort方法重写,可以自定义排序,也是内部类,后边会学习 swap(List<?> l ist, int i, int j)//对集合指定两个位置进行交换
copy(List<? super T> dest, List<? extends T> src) ;//对集合进行复制,注意新的集合空间必须大于等于旧的集合空间 emptyList() 返回为空的集合,不能添加数据 fill(List<? super T> l ist, T obj)//用指定的元素代替指定列表的所有元素。 max(Col lection<? extends T> col l)//根据其元素的 自然顺序返回给定集合的最大元素。 min(Col lection<? extends T> col l)//根据其元素的 自然顺序返回给定集合的最小元素。 replaceAl l(List l ist, T oldVal, T newVal)//将集合中某个值全部替换为指定值 reverse(List<?> l ist)//反转指定列表中元素的顺序。
shuffle(List<?> l ist) //使用默认的随机源随机排列指定的列表。
copy(dest,src)集合复制