集合框架
**概念:**集合是一种对象容器,用于存放对象
数组的缺点:
1.定长,一旦定义就不能被改变
2.数组中没有方法
3.只能存放相同的数据类型
集合的特点:
1.长度可以变化
2.有丰富的操作方法
3.集合只能存放引用数据类型
集合的分类
单列集合 (集合中一个元素保存一个数据) Collection
双列集合 (集合中一个元素保存两个数据) Map
集合的架构
Collection接口
单列集合的顶层接口
方法:
- add方法向集合集合中添加元素
- clear方法,清空集合中所有元素
- contains方法 判断集合是否包含某个元素
- isEmpty判断集合是否为空
- remove方法 移除集合中元素,返回boolean类型。如果集合中不包含次元素,则删除失败
- size()返回集合中元素的个数
- toArray将集合转换成数组。
- addAll 向一个集合中添加另一个集合
- containsAll 判断一个集合中是否包含另一个集合
- removeAll 从一个集合中移除另一个集合
- retainAll() 只保留在传入集合中有的元素
返回一个List对象(日常开发经常用到)
List strings = Arrays.asList(“a”, “b”, “c”);
System.out.println(strings);
public class Demo08 {
public static void main(String[] args) {
Collection coll=new ArrayList();
//添加
coll.add("张三");
coll.add(1);
coll.add("李四");
System.out.println(coll);
//移除
coll.remove("李四");
System.out.println(coll);
//是否包含
System.out.println(coll.contains("李四"));
System.out.println(coll.contains("张三"));
//元素个数
System.out.println(coll.size());
//转成数组
System.out.println(coll.toArray().length);
// //清除
// coll.clear();
// System.out.println(coll);
//是否为空
System.out.println(coll.isEmpty());
System.out.println("-------------------------------");
//
Collection coll1=new ArrayList();
coll1.add("1");
coll1.add("2");
coll1.add("3");
coll1.add("4");
Collection coll2=new ArrayList();
coll2.add("3");
coll2.add("4");
//添加指定集合的都有元素
coll1.addAll(coll2);
System.out.println(coll1);
//判断是否包含指定集合的所有元素
System.out.println(coll1.containsAll(coll2));
//仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
System.out.println(coll1.retainAll(coll2));
System.out.println(coll1);
//移除指定集合的所有元素
coll1.removeAll(coll2);
System.out.println(coll1);
//返回一个List对象(日常开发经常用到)
List<String> strings = Arrays.asList("a", "b", "c");
System.out.println(strings);
}
}
迭代器
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
迭代器原理
public class Demo09 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String s = (String) iterator.next();
if (s.equals("李四")){
//迭代器移除元素
iterator.remove();
}
System.out.println(s);
}
System.out.println("------------------");
System.out.println(list);
Iterator<String> iterator1 = list.iterator();
while (iterator1.hasNext()){
String s = iterator1.next();
System.out.println(s);
}
}
}
迭代器使用常见问题
- 1、迭代器迭代完成之后,迭代器的位置在最后一位。 所以迭代器只能迭代一次
- 2、迭代器在迭代的时候,不要调用多次next方法,可能会出错 NoSuchElementException
- 3、在迭代器迭代的时候,不能向集合中添加或者删除元素 ConcurrentModificationException
ArrayList类
常用方法:
- add(int index, E element)
- remove(int index)
- set(int index, E element)
- get(int index)
- size()
- subList(int beginIndex,int endIndex) 左闭右开
- list.listIterator();
package com.qf.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
*@title Demo02
*@description
*@author GaoQk
*@version 1.0
*@create 2023/8/2 11:23
*/
public class Demo02 {
public static void main(String[] args) {
ArrayList<String> arrList = new ArrayList<>();
arrList.add("张三");
arrList.add("李四");
arrList.add("王五");
//根据下标添加元素
arrList.add(1,"赵四");
System.out.println(arrList);
System.out.println("---------------");
//根据下标移除元素
arrList.remove(1);
System.out.println(arrList);
System.out.println("------------------");
//根据下标获取元素
System.out.println(arrList.get(1));
//根据下标修改元素
arrList.set(1,"赵四");
System.out.println(arrList);
//截取集合[),从a下标截取到b下标,不包含b,原来的集合不变,返回新的集合
List<String> list = arrList.subList(1, 2);
System.out.println(list);
System.out.println(arrList);
System.out.println("-------------------------");
// //ArrayList中的迭代器
// ListIterator<String> sli = arrList.listIterator();
// //往后移动
// while (sli.hasNext()){
// String s = sli.next();
// System.out.println(s);
// }
// //可以往前移动
// while (sli.hasPrevious()){
// String s = sli.previous();
// System.out.println(s);
// }
System.out.println("---------------------------------");
}
}
ArrayList遍历的4种方法:
//遍历
//1.普通for循环遍历
for (int i = 0; i < arrList.size(); i++) {
System.out.println(arrList.get(i));
}
//2.迭代器遍历
Iterator<String> iterator = arrList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//3.增强for循环,foreach
for (String s:arrList) {
System.out.println(s);
}
//4.ArrayList 特有的迭代器
//ArrayList中的迭代器
ListIterator<String> sli = arrList.listIterator();
//往后移动
while (sli.hasNext()){
String s = sli.next();
System.out.println(s);
}
//可以往前移动
while (sli.hasPrevious()){
String s = sli.previous();
System.out.println(s);
}
ArrayList实现了特有的迭代器
//4.ArrayList 特有的迭代器
//ArrayList中的迭代器
ListIterator<String> sli = arrList.listIterator();
//往后移动
while (sli.hasNext()){
String s = sli.next();
System.out.println(s);
}
//可以往前移动
while (sli.hasPrevious()){
String s = sli.previous();
System.out.println(s);
}
ArrayList底层实现原理:
ArrayList其底层实现使用数组 ,添加时才进行扩容,每次扩容到原来的1.5倍 ,查找快,增删慢
说明:第一次添加时,将数组长度扩容到10;不是第一次扩容,就判断如果有效个数size()+1大于数组长度,就需要扩容,每次扩容数组的一半
LinkedList类
常用的方法与ArrayList一致。自己独有一些向首尾添加移除等方法(可以模拟对列、堆栈等数据结构)
方法代码:
//LinkedList实际工作中很少用到
LinkedList<String> linkedList = new LinkedList<>();
//添加
linkedList.add("张三");
linkedList.add("李四");
System.out.println(linkedList);
//从首部添加
linkedList.addFirst("王五");
//从末尾添加
linkedList.addLast("赵六");
System.out.println(linkedList);
//获取
System.out.println(linkedList.get(0));
//获取头部
System.out.println(linkedList.getFirst());
//获取尾部
System.out.println(linkedList.getLast());
System.out.println("---------------------");
模拟队列
//模拟队列,先进先出
linkedList = new LinkedList<>();
//向队列的尾部添加元素
linkedList.offer("张三");
linkedList.offer("李四");
linkedList.offer("王五");
// //对LinkedList,可以移除元素
// System.out.println(linkedList.poll());
// System.out.println(linkedList.poll());
// System.out.println(linkedList.poll());
//获取但不移除队列的头部元素
System.out.println(linkedList.peek());
System.out.println(linkedList.element());
System.out.println(linkedList);
模拟栈
/模拟栈 先进后出
linkedList = new LinkedList<>();
//将元素推入此列表所表示的堆栈
linkedList.push("张三");
linkedList.push("李四");
linkedList.push("王五");
//从栈的末尾弹出,并移除对象
System.out.println(linkedList.pop());
System.out.println(linkedList);
LinkedList实现原理
LinkedList底层使用双向链表实现(增删快、查询慢)
堆栈和队列结构
Vector类
与ArrayList
的方法基本一致
ArrayList、
LinkedList、
Vector 的区别:
- ArrayList和Vector底层使用数组实现(增删慢、查询快)
- ArrayList是当添加元素的时候,才会扩容数组,默认长度为10, Vector是当创建对象的是,就创建长度为10的数组
- ArrayList线程不安全,效率高 Vector是线程安全的,效率低
- LinkedList底层使用双向链表实现(增删快、查询慢)
HashSet类
常用方法与Collection接口中定义的方法一致
特点:
- 无序 (插入顺序)
- 无下标
- 不可重复
方法:
HashSet<String> hashSet = new HashSet<>();
hashSet.add("zs");
hashSet.add("ls");
hashSet.add("ww");
hashSet.add("zl");
System.out.println(hashSet);
//for循环遍历
for (String s:hashSet){
System.out.println(s);
}
//迭代器遍历,如果删除需要用迭代器删除
Iterator<String> iterator = hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
iterator.remove();
}
去重原理:先判断hashcode,在判断equals()方法,两者都相等,才是同一个对象,否则不是
判断对象是否相同要重写hashcode()方法和equals()方法
//HashSet去重原理:先判断hashcode,在判断equals()方法,两者都相等,才是同一个对象,否则不是
HashSet<User> hashSet = new HashSet<>();
hashSet.add(new User("张三",10));
hashSet.add(new User("张三",10));
// hashSet.add(new User("lisi",20));
// hashSet.add(new User("王五",15));
System.out.println(hashSet);
LinkedHashSet类
特点::
- 1、有序
- 2、无下标
- 3、不可重复
与父类的方法一致,去重的原理,也与父类一致
TreeSet类
TreeSet特点:
- 1、无序(但是有字典顺序)
- 2、无下标
- 3、不可重复
常用方法
与HashSet
类的方法一致
特点:
使用TreeSet
集合存储对象的时候,对象必须要实现Comparable接口
实现原理
TreeSet
在存储元素的时候,会调用compareTo
方法。两个作用: - 1、排序: 返回值大于0升序,返回值小于0降序
- 2、去重(返回值为0)
TreeSet
认为返回0,两个对象就是相同的对象 - 3、写成表达式,要根据实现情况判断是升序还是降序(this在前面就是升序,反之降序)
public class Demo01 {
public static void main(String[] args) {
//TreeSet 去重,按字典顺序排序(a,b,c)
TreeSet<String> treeSet = new TreeSet<>();
treeSet.add("zs");
treeSet.add("ls");
treeSet.add("ww");
treeSet.add("zs");
System.out.println(treeSet);
System.out.println("----------------------");
//增强for循环
for (String s : treeSet) {
System.out.println(s);
}
Iterator<String> iterator = treeSet.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
TreeSet<Person> treeSet1 = new TreeSet<>();
treeSet1.add(new Person("zs",20));
treeSet1.add(new Person("ls",80));
treeSet1.add(new Person("zs",10));
treeSet1.add(new Person("ww",10));
System.out.println(treeSet1);
}
}
//必须实现Comparable接口
class Person implements Comparable<Person>{
String name;
Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//实现compareTo方法
@Override
public int compareTo(Person o) {
if (!this.name.equals(o.name)){
return this.name.compareTo(o.name);
}else {
return this.age-o.age;
}
}
}
Collections工具类
常用的方法:
Collections.reverse(List<?> list)
- 将集合中的元素反转
Collections.shuffle(List<?> list)- 将集合中的元素随机打乱
Collections.sort(List<?> list) - 将集合中的元素排序
- 自定义排序规则,实现Comparator接口
- 将集合中的元素随机打乱
//反转
List<Integer> list = Arrays.asList(1, 2, 5, 1, 3);
Collections.reverse(list);
System.out.println(list);
//随机打乱
List<Integer> list1 = Arrays.asList(1, 8, 27, 63, 1);
Collections.shuffle(list1);
System.out.println(list1);
sort()方法排序
//sort()排序
List<String> list = Arrays.asList("abc", "aa", "df", "asc");
Collections.sort(list);
System.out.println(list);
List<Integer> list1 = Arrays.asList(1, 9, 4, 8, 7, 2);
Collections.sort(list1);
System.out.println(list1);
List<Student> list2 = Arrays.asList(new Student("zs", 20), new Student("ls", 20), new Student("zs", 21));
Collections.sort(list2, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if (!o1.name.equals(o2.name)){
return o1.name.compareTo(o2.name);
}
return o1.age-o2.age;
}
});
System.out.println(list2);
}
}
class Student{
String name;
Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
Map集合
Map集合特点
- Map集合是双列集合,由key和value组成。称之为键值对
- 键的特点:无序,无下标,不重复。
- 值的特点:无序,无下标,可重复
Map集合体系结构
HashMap
HashMap基本使用
常用方法
- put(K key, V value)
- get(Object key)
- Set keySet()
- Collection values()
- Set<Map.Entry<K,V>> entrySet() 用于遍历
- boolean containsKey(Object key) 是否包含key
- boolean containsValue(Object value) 是否包含value
- V remove(Object key)
- int size()
HashMap<String, String> map = new HashMap<>();
//添加
map.put("cn","中国");
map.put("rb","日本");
map.put("jp","小日本");
map.put("cn","中华人民共和国");
//获取value
System.out.println(map.get("cn"));
//移除
String s = map.remove("rb");
System.out.println(s);
System.out.println(map);
//判断key和value是否存在
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("小日本"));
//是否为空
System.out.println(map.isEmpty());
//元素个数
System.out.println(map.size());
//遍历
Set<String> key = map.keySet();
for (String s1:key){
System.out.println(map.get(s1));
}
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String,String> entry:entries){
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
//清空
map.clear();
System.out.println(map);
HashMap的实际应用
public class Demo05 {
public static void main(String[] args) {
//用HashMap代替实体类
Stu stu1 = new Stu("zs", 20);
System.out.println(stu1);
HashMap<String, Object> map = new HashMap<>();
map.put("name","zs");
map.put("age",20);
System.out.println(map);
//集合的嵌套使用
List<Stu> stus = Arrays.asList(new Stu("ls", 10), new Stu("ww", 10));
System.out.println(stus);
HashMap<String, Object> map1 = new HashMap<>();
HashMap<String, Object> map2 = new HashMap<>();
map1.put("name","ls");
map1.put("age",10);
map2.put("name","ww");
map2.put("age",10);
List<HashMap<String, Object>> list = Arrays.asList(map1, map2);
System.out.println(list);
//集合嵌套使用
List<String> list1 = Arrays.asList("济南", "青岛", "烟台");
List<String> list2 = Arrays.asList("南京", "苏州", "无锡");
HashMap<String, Object> shandong = new HashMap<>();
HashMap<String, Object> jiangsu = new HashMap<>();
shandong.put("山东",list1);
jiangsu.put("江苏",list2);
List sd = (List) shandong.get("山东");
List js = (List) jiangsu.get("江苏");
System.out.println(sd);
System.out.println(js);
}
}
class Stu{
String name;
Integer age;
public Stu(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
HashMap的相关实现(重要)
HashMap底层是用Hash表实现,分为数组+链表+红黑树
HashMap 默认初始长度16 , 阈值12 扩容因子 0.75
如果元素个数大于阈值,数组的长度增长一倍,阈值增长一倍
当链表的元素个数大于等于8,数组的长度大于等于64,把链表转化成红黑树
扩容因子0.75?
大于0.75,空间利用率高,查询慢
小于0.75,空间利用率低,查询快
put方法是有返回值,是覆盖,把原来的value返回 ,不是覆盖,返回null
Hashtable
Hashtable常用方法与HashMap一致
HashMap与Hashtable区别:
- 1、Hashtable是线程安全的,HashMap是线程不安全的
- 2、Hashtable中不允许存储null作为key和value,而HashMap可以
在实际开发中一般都是用HashMap。考虑线程安全使用ConCurrentHashMap
泛型的使用
泛型类
泛型类 类名
public class Box<T> { //T:表示任意的java类型 E、K、V
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
泛型接口
泛型接口 接口名
public interface MyInterface<T> {
public void show(T t);
}
泛型方法
泛型方法 public T 方法名(T t,…){}
//泛型可以作为参数,(必须得先定义 <T> )
public <T> void m1(T t) {
}
泛型上下边界
语法:
- 上边界 ? extends 类型 类型是?的父类
- 下边界 ? super 类型 类型是?的子类
public class Demo01 {
//? 表示不确定类型 此时的?表示Object
public static void test01(List<?> list) {
}
/**
* 定义泛型上边界
*
* <? extends 类型>
*/
public static void test02(List<? extends Number> list) {
}
/**
* 定义泛型下边界
*
* <? super 类型>
*/
public static void test03(List<? super Number> list) {
}
public static <T> void test04(List<? extends Comparable<T>> list) {
}
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();
List<Number> list3 = new ArrayList<Number>();
List<Object> list4 = new ArrayList<Object>();
test01(list1);
test01(list2);
test01(list3);
test01(list4);
//test02(list1); //错误,方法定义泛型的上边界,泛型只能是Number及其Number子类
test02(list2);
test02(list3);
//test02(list4); //错误,方法定义泛型的上边界,泛型只能是Number及其Number子类
//test03(list1); //错误,方法定义泛型的下边界,泛型只能是Number及其Number父类
//test03(list2);
test03(list3);
test03(list4);
test04(list1);
test04(list2);
//test04(list3); //错误,方法定义泛型的上边界,泛型必须实现Comparable接口
//test04(list4); //错误,方法定义泛型的上边界,泛型必须实现Comparable接口
}
}