Java集合体系
- 一、概念
- 二、集合分类 - java.util
- 1、单列集合:一条数据只有一列
- 1.1 List集合
- 1.2 Set集合
- 2、双列集合:一条数据有两列
- 2.1 特点
- 2.2 Map接口的常用方法
- 2.3 Map接口的常用实现类
- 2.3.1 HashMap:key元素无序
- 2.3.2 LinkedHashMap:有序,加入有序
- 2.3.3 Hashtable:无序 Properties (Hashtable的子类):一般是用来读取一些配置文件数据的
- 2.3.4 TreeMap:key的大小有序 key值必须都有比较器
一、概念
Java集合和数组一样,都是存放一组相同类型数据的容器。Java集合和数组的不同点在于以下几点。
1、虽然Java和数组都是存放一组相同类型的数据,但是数组是任何一种类型都可以存储,集合只能存放引用数据类型的数据(集合底层使用泛型来定义存储的数据类型)。
2、数组有一个长度,长度一旦确定不可改变。Java集合容量没有限制 - 自动扩容的。
【补充】StringBuffer、StringBuilder底层也可以自动扩容:借助Arrays.copyof(),底层又借助了System.arrayCopy()。
二、集合分类 - java.util
在Java当中,提供了各种各样的集合用来满足不同的业务需求。
1、单列集合:一条数据只有一列
所有的单列集合都是Collection接口的子类,Collection封装了很多单列集合共有的方法,只不过这些方法基本上都是抽象方法。
单列集合Collection继承了Iterable,遍历Java集合。可通过迭代器、增强for循环进行遍历。
package com.nuc.kang.collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection接口给我们提供的单列集合常用的方法
* size():int 获取集合存放的元素个数
* isEmpty():boolean 判断集合是否为空集合
* contains(Object):boolean 判断集合是否包含该元素
* iterator():Iterator<E> 获取集合的迭代器,用于遍历集合
* toArray():Object[] 将集合转换为数组
* toArray(T[]):T[] 将集合转换为指定类型的数组
* add(E):boolean 将元素加到集合当中
* remove:Object 移除某个元素
* clear() 清空集合
* @author 冰霜中的独舞
* @version 2023年7月3日 下午7:27:30
*
*/
public class Demo01 {
public static void main(String[] args) {
Collection<Integer> col = new ArrayList<>();
System.out.println(col.size());
System.out.println(col.isEmpty());
col.add(1);
System.out.println(col.contains(1));
col.add(2);
/**
* 遍历集合:两种遍历方式
* 1、增强的for循环
* 2、迭代器也可以遍历 获取迭代器 借助迭代器的hasNext判断有没有下一条数据 然后再借助next获取下一条数据
*/
for(Integer ele : col) {
System.out.println(ele);
}
Iterator<Integer> iterator = col.iterator();
while(iterator.hasNext()) {
Integer next = iterator.next();
System.out.println(next);
}
col.remove(2);
System.out.println(col);
col.clear();
System.out.println(col);
col.add(1);
col.add(8);
Object[] array = col.toArray();
System.out.println(Arrays.toString(array));
Integer[] array1 = new Integer[col.size()];
col.toArray(array1);
System.out.println(Arrays.toString(array1));
}
}
单列集合又细分为两种,都是Collection接口的一个子接口:
1.1 List集合
-
List接口类型的集合:所有数据可以重复,而且是有序的 - 加入有序
-
提供几个可以使用索引进行取值赋值的操作
-
List接口的三个实现类:
- Vector:一般扩容为原先的2倍,如果有扩容因子,那么就是扩容为原先的长度 + 扩容因子
import java.util.Vector; /** * List的实现类: list的实现类除了LinkedList增加了几个特殊方法外, * Vector和ArrayList基本没在接口之上再增加新的方法。 * Vector<>(): * 无参构造器底层调用this(10),底层先给你创建一个容量为10的数组存放元素,扩容因子也是0 * Vector(int initialCapacity): * 有参构造器底层调用this(initialCapacity,0):底层给你创建一个指定长度的数组,顺序再指定一个扩容因子为0 * Vector(int initialCapacity,int capacityIncrement):底层创建一个指定长度的数组,指定数值的扩容因子 * * Vector底层扩容的时候默认扩容为原先的一倍,但是如果扩容因子不为0的话,那么扩容为就数组长度+扩容因子 */ public class ListImpleDemo01 { public static void main(String[] args) { Vector<Integer> vec = new Vector<>(); vec.add(1); vec.add(1,2); vec.add(3); vec.add(1); System.out.println(vec); } }
-
ArrayList:一般扩容为原先的1.5倍
以上两种是底层借助数组实现,数据可以重复,而且有序 - 加入有序
import java.util.ArrayList; /** * ArrayList创建 * ArrayList(): * 底层会创建一个长度为10的数组存放数据, * 但是一定要注意,长度为10的数组并不是在构造器中直接创建的,而是在集合第一次增加元素的时候创建的 * ArrayList(int capacity) * ArrayList(Collection) */ public class ListImpleDemo02 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.addAll(new ArrayList<Integer>(20)); } }
-
LinkedList:扩容是通过Node内部类完成
底层借助双向链表来实现,数据可以重复,而且加入有序
import java.util.LinkedList; /** * * LinkedList也是JavaList集合体系的一个实现类,只不过LinkedList底层不是借助数组来存储数据的 * 而是借助双向链表去存储数据,而且通过双向链表维护数据的加入顺序 * * LinkedList因为使用双向链表(prev,datasource,next)来存储数据,在类中提前把链表的头部节点和尾部节点已经提前定义出来了 * 因此LinkedList在Collection、List接口之上提供了四个比较特殊的方法,可以直接对集合的头部节点和尾部节点进行操作 * addFirst(E)--在头部增加数据 * addLast(E)--在尾部增加数据 * add(E)--默认在尾部增加数据 * removeFirst()--移除头部元素 * removeLast()--移除尾部元素 * * LinkedList一般用在频繁的修改和数据变更下。 * ArrayList更适合使用在频繁的数据查找下。 */ public class ListImpleDemo03 { public static void main(String[] args) { LinkedList<Integer> list = new LinkedList<>(); list.add(1); System.out.println(list); } }
1.2 Set集合
-
Set接口类型的集合:数据不允许重复,而且数据不一定有序
-
Set接口的三个实现类:
- HashSet: 不允许重复,元素是无序的
- LinkedHashSet:不允许重复,但是元素是有序的,加入有序
- TreeSet:不允许重复,但是元素有序的,大小有序,treeset集合中元素必须有比较器
-
Set判重验证
package com.nuc.kang.collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
/**
* Set集合也是一个单例集合,是Collection的子接口
* Set接口集合体系没有提供任何的多余方法,使用的集合增加数据方法都是Collection提供的
* Set接口集合虽然没有提供多余的方法,但是提供了存储数据的特性,元素不能重复
*
* Set集合去判断两个元素是否重复借助Java的两个方法完成的:
* (1)hashCode:返回一个整数类型的值,默认返回的是对象在堆区的地址。
* (2)equals方法:比较两个对象是否值相等,默认情况下比较两个对象的地址相等。
* 【注意】在Java中有要求的,两个对象通过equals返回比较为true的话,那么两个对象的hashCode方法必须返回相同的值
* 如果两个对象的hashCode值不一样 那么两个对象一定不相等,如果两个对象的hashCode值一样的,不一定相等。
* 判断规则:
* (1)set集合在添加元素时,先通过待添加元素的hashCode值和集合中的每一个元素的hashCode值做比较,如果hashCode值都不一样,那么认为元素不重复,直接添加到集合当中了
* (2)如果hashCode值重复了,那么调用equals方法看返回结果,返回结果为true,那么重复 不添加 如果返回结果为false 那么就是不重复 添加
*
*/
public class SetDemo01 {
public static void main(String[] args) {
//Set<Integer> set = new HashSet<>();//[1, 19, 7, 8, 10]
//Set<Integer> set = new LinkedHashSet<>();//[1, 10, 19, 8, 7]
Set<Integer> set = new TreeSet<>();//[1, 7, 8, 10, 19]
set.add(1);
set.add(1);
set.add(1);
set.add(10);
set.add(19);
set.add(8);
set.add(7);
System.out.println(set);
}
}
package com.nuc.kang.collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
/**
* set判重验证
*/
public class SetDemo02 {
public static void main(String[] args) {
Set<Student> set = new HashSet<>();
Student stu = new Student("zs", 18, "s001");
Student stu1 = new Student("zs", 18, "s001");
set.add(stu);
set.add(stu1);
System.out.println(set);
}
}
class Student {
private String name;
private Integer age;
private String sno;
public Student(String name, Integer age, String sno) {
super();
this.name = name;
this.age = age;
this.sno = sno;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sno=" + sno + "]";
}
@Override
public int hashCode() {
return Objects.hash(age, name, sno);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
return Objects.equals(age, other.age) && Objects.equals(name, other.name) && Objects.equals(sno, other.sno);
}
}
-
TreeSet实现大小排序:
- 实现Comparable接口
package com.nuc.kang.collection; import java.util.HashSet; import java.util.Objects; import java.util.Random; import java.util.Set; class Student implements Comparable<Student>{ private String name; private Integer age; private String sno; public Student(String name, Integer age, String sno) { super(); this.name = name; this.age = age; this.sno = sno; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", sno=" + sno + "]"; } @Override public int hashCode() { return Objects.hash(age, name, sno); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; return Objects.equals(age, other.age) && Objects.equals(name, other.name) && Objects.equals(sno, other.sno); } @Override public int compareTo(Student o) { if(this.age > o.age) { return 1; }else if(this.age < o.age) { return -1; }else { return 0; } } }
package com.nuc.kang.collection; import java.util.Comparator; import java.util.Set; import java.util.TreeSet; public class SetDemo03 { public static void main(String[] args) { Set<Student> set = new TreeSet<>(); Student stu = new Student("zs", 20, "s001"); Student stu1 = new Student("ls", 18, "s002"); Student stu2 = new Student("ww", 15, "s003"); set.add(stu); set.add(stu1); set.add(stu2); System.out.println(set); } }
- 创建Comparator的比较器
package com.nuc.kang.collection; import java.util.Objects; import java.util.Random; import java.util.Set; class Student { private String name; private Integer age; private String sno; public Student(String name, Integer age, String sno) { super(); this.name = name; this.age = age; this.sno = sno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSno() { return sno; } public void setSno(String sno) { this.sno = sno; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", sno=" + sno + "]"; } @Override public int hashCode() { return Objects.hash(age, name, sno); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; return Objects.equals(age, other.age) && Objects.equals(name, other.name) && Objects.equals(sno, other.sno); } }
package com.nuc.kang.collection; import java.util.Comparator; import java.util.Set; import java.util.TreeSet; public class SetDemo03 { public static void main(String[] args) { //TreeSet实现元素大小排序,在TreeSet构造器里面传上一个匿名内部类的comparator的比较器 Set<Student> set = new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { if(o1.getAge() > o2.getAge()) { return 1; }else if(o1.getAge() < o2.getAge()) { return -1; }else { return 0; } } }); Student stu = new Student("zs", 20, "s001"); Student stu1 = new Student("ls", 18, "s002"); Student stu2 = new Student("ww", 15, "s003"); set.add(stu); set.add(stu1); set.add(stu2); System.out.println(set); } }
Collections - Java给我们提供的封装了单列集合常用的工具方法的工具类 - 提供的方法针对List集合体系
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Demo01 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(3,2,1,5,4,6);
Collections.sort(list);//默认升序
System.out.println(list);
//降序
List<Integer> list3 = Arrays.asList(55,22,44,11,99);
Collections.sort(list3, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 > o2 ? -1:(o1 < o2 ? 0:1);
}
});
System.out.println(list3);
//二分查找
int i = Collections.binarySearch(list, 1);
System.out.println(i);
//构建一个空集合
List<Object> list2 = Collections.emptyList();
//数组反转
Collections.reverse(list);
System.out.println(list);
//对集合顺序打乱
Collections.shuffle(list);
System.out.println(list);
}
}
2、双列集合:一条数据有两列
所有的双列集合都是Map接口的子类
2.1 特点
-
每一行数据都是有两列组成的,其中第一列称为key,第二列称为value
-
其中在Map集合当中,key值不允许重复,value允许重复的。Map集合底层所有的key值通过Set集合来进行存储的,Value值通过Collection集合进行存储的
-
如果Map集合增加了重复性的key值,会把原有的key值对应的value数据替换掉
2.2 Map接口的常用方法
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Map集合常用方法、map集合的定义方式
*/
public class Demo01 {
public static void main(String[] args) {
Map<String,Double> map = new HashMap<>();
System.out.println(map.size());//查看集合的元素个数
System.out.println(map.isEmpty());//判断map集合是否为空
///map集合添加元素
map.put("香酥鸡", 90.3);
map.put("糖醋丸子", 18.0);
map.put("鱼香肉丝", 26.4);
map.put("鸡公煲", 36.5);
map.put("香酥鸡", 45.3);
map.put("北京烤鸭", 76.4);
System.out.println(map);
//判断map集合是否包含某个key值
System.out.println(map.containsKey("鸡公煲"));
System.out.println(map.containsKey("清蒸鲈鱼"));
//根据key值获取map集合中对应的value值 如果key值不存在,那么会得到一个null值
Double price = map.get("鱼香肉丝");
System.out.println(price);
//map集合为了预防获取不存在的key值导致空指针问题,提供了一个获取的方法并且防止null值
Double orDefault = map.getOrDefault("鱼香肉丝", 0.0);
System.out.println(orDefault);
//清空集合
// map.clear();
// System.out.println(map);
//map集合元素替换--key对应的value
map.replace("鱼香肉丝", 158.0);
System.out.println(map);
//根据key移除map集合中的某个元素
Double remove = map.remove("北京烤鸭");
System.out.println(map);
/**
* Map集合的遍历:
* keySet():Set<K> 获取map集合中的所有key值,返回的是set集合
* entrySet():Set<Entry<K,V>>:获取map集合中所有元素,变成一个set集合,只不过map集合每一条的key和value使用内部类Entry封装起来
*/
Set<String> set = map.keySet();
for(String key : set) {
Double double1 = map.get(key);
System.out.println(key + "=" + double1);
}
Set<Entry<String,Double>> entrySet = map.entrySet();
for(Entry<String, Double> entry : entrySet) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
使用Map集合写的一个菜单管理系统:
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
/**
* 程序启动 要求可以实现在控制台对菜单进行增删改查
* 1、增加菜品 2、修改菜品价格 3、查询单个菜品 4、查询所有菜品 5、删除菜品
*/
public class MenuManager {
public static void main(String[] args) {
//定义一个存放菜品的容器
Map<String, Double> cd = new HashMap<String, Double>();
Scanner sc = new Scanner(System.in);
a:while(true) {
System.out.println("||================================控制台=========================================||");
System.out.println("||========1、增加菜品 2、修改菜品价格 3、查询单个菜品 4、查询所有菜品 5、删除菜品 6、退出系统=========||");
System.out.println("||================================控制台=========================================||");
System.out.print("请输入要执行的操作:");
int num = sc.nextInt();
switch (num) {
case 1 :
System.out.print("请输入一个菜名:");
String dish = sc.next();
System.out.print("请输入菜的价格:");
double price = sc.nextDouble();
cd.put(dish, price);
System.out.println("菜品添加成功!");
break;
case 2 :
System.out.print("请输入一个菜名:");
String dish1 = sc.next();
if(cd.containsKey(dish1)) {
System.out.print("请输入要修改菜名的价格:");
Double price1 = sc.nextDouble();
cd.replace(dish1, price1);
System.out.println("菜品价格修改成功!");
}else {
System.out.println("您输入的菜品不存在!");
}
break;
case 3 :
System.out.print("请输入一个菜名:");
String dish2 = sc.next();
if(cd.containsKey(dish2)) {
System.out.println("您要查询的菜品为:" + dish2 + ",价格为:" + cd.get(dish2));
}else {
System.out.println("您输入的菜品不存在!");
}
break;
case 4 :
Set<Entry<String,Double>> entrySet = cd.entrySet();
for(Entry<String,Double> entry : entrySet) {
System.out.println("菜品为:" + entry.getKey() + "价格为:" + entry.getValue());
}
break;
case 5 :
System.out.print("请输入您要删除的菜品:");
String dish3 = sc.next();
if (cd.containsKey(dish3)) {
cd.remove(dish3);
System.out.println("您输入的菜品已删除!");
}else {
System.out.println("您输入的菜品不存在!");
}
break;
case 6:
System.out.println("您的系统已退出!");
break a;
default:
System.out.println("输入的操作不存在,请重新输入!");
break;
}
}
}
}
2.3 Map接口的常用实现类
public class Demo02 {
public static void main(String[] args) {
Map<String,Double> map = new HashMap<>();
map.put("香酥鸡", 90.3);
map.put("糖醋丸子", 18.0);
map.put("鱼香肉丝", 26.4);
map.put("鸡公煲", 36.5);
map.put("香酥鸡", 45.3);
map.put("北京烤鸭", 76.4);
System.out.println(map);
}
}
2.3.1 HashMap:key元素无序
2.3.2 LinkedHashMap:有序,加入有序
2.3.3 Hashtable:无序 Properties (Hashtable的子类):一般是用来读取一些配置文件数据的
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
/**
* Properties是一个map集合,map集合一般不是当作正常的map集合使用
* 而是专门用来加载一个叫做xxx.properties的一个配置文件中的数据为key-value键值对的。
* 每一行数据必须是如下的格式:
* key=value
*/
public class PropertiesStudy {
public static void main(String[] args) throws FileNotFoundException, IOException {
/**
* key-value均是Object字符串
*/
Properties prop = new Properties();
prop.put("zs", 1);
System.out.println(prop);
/**
* prop除了map集合有的方法,还多了三个方法:
* load()
* setProperty(String key,String value)===put
* getProperty(String key)===get
*/
prop.load(new FileInputStream("D:\\2023PracticalTraining\\software\\workspace\\eclipseworkspace\\java-study-619\\project.properties"));
System.out.println(prop);
String value = prop.getProperty("username");
System.out.println(value);
prop.setProperty("username","ls");
System.out.println(prop);
}
}
username=zhangsan
password=123456