Java集合的基本使用
一、Collection接口
Collection接口中常用的关键方法
- add:添加单个元素
- remove:删除指定元素
- contains:查找元素是否存在
- size:获取元素个数
- isEmpty:判断是否为空
- clear:清空
- addAll:添加多个元素
- containsAll:查找多个元素是否都存在
- removeAll:删除多个元素
(1)List接口
List接口中添加了一些根据索引来操作集合元素的方法:
- void add(int index, Object ele):在index位置插入ele元素
- Boolean addAll(int index,Collection eles):在index位置将eles中所有元素插入进来
- Object get(int index):获取index位置的元素
- int indexOf(Object obj):获取obj在集合中首次出现的位置
- int lastIndexOf(Object obj):获取obj在集合中末次出现的位置
- Object remove(int index):删除index位置的元素,并返回此元素
- Object set(int index, Object ele):将index位置的元素设置为ele,相当于替换
- List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
1.ArrayList
- ArrayList可以存放空元素null,且是可以存放多个空值。
- 底层是数组,效率高,线程不安全,适用于改查多,增删少的情况。
import java.util.*;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> li = new ArrayList<>();
li.add(1); // 添加元素
li.add(100);
li.remove(0); // 删除索引为0的元素
//li.remove(new Integer(100)); // 删除值为100的元素
Boolean isEmpty = li.isEmpty(); // 判断是否为空
int size = li.size();
if (li.contains(100)) { // 判断是否存在指定元素
System.out.println("100存在");
}
li.clear(); // 清空集合中所有元素
List<Integer> ll = new ArrayList<>();
for (int i = 0; i < 5; i++)
ll.add(i);
li.addAll(ll); // 往集合中添加多个元素
Boolean isContainsAll = li.containsAll(ll); // 查找多个元素是否都存在
li.removeAll(ll); // 删除多个元素
}
}
2.LinkedList
- 底层是双向链表,适用于改查少,增删多的情况。
import java.util.*;
public class Main {
public static void main(String[] args) {
LinkedList<Integer> li = new LinkedList<>();
li.add(1); // 添加元素
li.add(100);
li.remove(0); // 删除索引为0的元素
//li.remove(new Integer(100)); // 删除值为100的元素
Boolean isEmpty = li.isEmpty(); // 判断是否为空
int size = li.size();
if (li.contains(100)) { // 判断是否存在指定元素
System.out.println("100存在");
}
li.clear(); // 清空集合中所有元素
List<Integer> ll = new LinkedList<>();
for (int i = 0; i < 5; i++)
ll.add(i);
li.addAll(ll); // 往集合中添加多个元素
Boolean isContainsAll = li.containsAll(ll); // 查找多个元素是否都存在
li.removeAll(ll); // 删除多个元素
}
}
3.Vector
相比于ArrayList和LinkedList,Vector是线程安全的,适用于在多线程下使用。
import java.util.*;
public class Main {
public static void main(String[] args) {
Vector<Integer> li = new Vector<>();
li.add(1); // 添加元素
li.add(100);
li.remove(0); // 删除索引为0的元素
//li.remove(new Integer(100)); // 删除值为100的元素
Boolean isEmpty = li.isEmpty(); // 判断是否为空
int size = li.size();
if (li.contains(100)) { // 判断是否存在指定元素
System.out.println("100存在");
}
li.clear(); // 清空集合中所有元素
List<Integer> ll = new Vector<>();
for (int i = 0; i < 5; i++)
ll.add(i);
li.addAll(ll); // 往集合中添加多个元素
Boolean isContainsAll = li.containsAll(ll); // 查找多个元素是否都存在
li.removeAll(ll); // 删除多个元素
}
}
(2)Set接口
Set接口和方法:
- Set接口无序(添加和取出元素的顺序不一样),没有索引,不支持随机访问
- 和List接口一样,Set接口也是Collection的子接口,因此常用方法和Collection接口一样
- Set接口的遍历也可以使用迭代器和增强for循环,但是不能用索引获取
- 不能有重复的元素/对象
1.HashSet
基本说明:
- HashSet实现了Set接口,底层实际上是HashMap
- 可以存放null值,但是只能存放一个(Set中的元素不能重复)
- HashSet不保证元素是有序的,取决于hash后,再确定索引的结果
- 不能有重复的元素/对象
注意事项:
- 在存储对象进HashSet时,对象重写equals方法一定要重写hashCode方法,不然就会出现即使两个对象里面的数据一模一样,但是都可以存进HashSet集合中,因为如果没有重写HashCode方法,对象会使用父类Object类的hashCode方法,而Object的HashCode方法是根据地址来计算的,一定不会一样
- ==使用的比较地址就是用的hashcode()
import java.util.*;
public class Main {
public static void main(String[] args) {
HashSet<Stu> hashSet = new HashSet<>();
hashSet.add(new Stu(1));
hashSet.add(new Stu(6));
hashSet.add(new Stu(5));
hashSet.add(new Stu(4));
hashSet.add(new Stu(3));
hashSet.add(new Stu(8));
hashSet.add(new Stu(7));
hashSet.add(new Stu(2));
hashSet.add(new Stu(1));
hashSet.add(new Stu(2));
for (Stu s : hashSet) {
System.out.println(s);
}
/*
打印顺序:跟插入顺序不一致
id=1
id=2
id=3
id=4
id=5
id=6
id=7
id=8
*/
}
}
class Stu {
public int id;
public Stu(int id) {
this.id = id;
}
@Override
public String toString() {
return "id=" + this.id;
}
// 需要重写hashCode()和equals()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Stu stu = (Stu) o;
return id == stu.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
2.LinkedHashSet
基本说明:
- LinkedHashSet是HashSet的子类
- LinkedHashSet底层是一个LinkedHashMap,底层维护了数组+双向链表
- LinkedHashSet根据元素的hashCode来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序来保存的
- LinkedHashSet不允许添加重复元素
import java.util.*;
public class Main {
public static void main(String[] args) {
LinkedHashSet<Stu> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(new Stu(1));
linkedHashSet.add(new Stu(6));
linkedHashSet.add(new Stu(5));
linkedHashSet.add(new Stu(4));
linkedHashSet.add(new Stu(3));
linkedHashSet.add(new Stu(8));
linkedHashSet.add(new Stu(7));
linkedHashSet.add(new Stu(2));
linkedHashSet.add(new Stu(1));
linkedHashSet.add(new Stu(2));
for (Stu s : linkedHashSet) {
System.out.println(s);
}
/*
打印顺序:跟插入顺序一致
id=1
id=6
id=5
id=4
id=3
id=8
id=7
id=2
*/
}
}
class Stu {
public int id;
public Stu(int id) {
this.id = id;
}
@Override
public String toString() {
return "id=" + this.id;
}
// 需要重写hashCode()和equals()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Stu stu = (Stu) o;
return id == stu.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
二、集合遍历方式
(1)迭代器
Iterator
对象称为迭代器,主要用于遍历Collection集合中的元素。- 所有实现了Collection接口的集合类都有一个Iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
- Iterator仅用于遍历集合,Iterator本身并不存储对象。
- 迭代器的执行原理:指针不断下移,直到遍历完集合中的元素。
import java.util.*;
public class Main {
public static void main(String[] args) {
Collection<Book> col = new ArrayList<>();
col.add(new Book("西游记"));
col.add(new Book("三国演义"));
col.add(new Book("红楼梦"));
Iterator<Book> it = col.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
// 当退出while循环后,这时iterator迭代器,指向最后的元素
// iterator.next(); --> NoSuchElementException
// 如果希望再次遍历,需要重置我们的迭代器
it = col.iterator();
}
}
class Book {
private String name;
public Book(String name) {
this.name = name;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
'}';
}
}
(2)增强for循环
增强for的底层仍然是迭代器,在for循环端点debug就可以看到了,会调用Iterator,增强for可以看成简易版的迭代器。
import java.util.*;
public class Main {
public static void main(String[] args) {
Collection<Book> col = new ArrayList<>();
col.add(new Book("西游记"));
col.add(new Book("三国演义"));
col.add(new Book("红楼梦"));
for (Book book : col) {
System.out.println(book);
}
}
}
class Book {
private String name;
public Book(String name) {
this.name = name;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
'}';
}
}
三、Map
Map基本说明:
- Map与Collection并列存在,用于保存具有映射关系的数据key-value
- Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
- Map中的key不允许重复,原因和HashSet一样
- Map中的value可以重复
- Map中的key和value均可以为null,但是key为null只能有一个,value为null可以有多个
- 常用String类作为Map的key
- key和value之间存在单向一对一的关系,即通过指定的key总能找到对应的value
Map接口常用的关键方法:
- put:添加
- remove:根据键删除映射关系
- get:根据键获取值
- size:获取元素个数
- isEmpty:判断个数是否为0
- clear:清除所有元素
- containsKey:查看键是否存在
Map的六大遍历方式:
import java.util.*;
public class Main {
public static void main(String[] args) {
Map map = new HashMap();
map.put("邓超", "孙俪");
map.put("王宝强", "马蓉");
map.put("宋喆", "马蓉");
map.put("刘令博", null);
map.put(null, "刘亦菲");
map.put("鹿晗", "关晓彤");
//第一组: 先取出 所有的Key , 通过Key 取出对应的Value
Set keyset = map.keySet();
//(1) 增强for
System.out.println("-----第一种方式-------");
for (Object key : keyset) {
System.out.println(key + "-" + map.get(key));
}
//(2) 迭代器
System.out.println("----第二种方式--------");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "-" + map.get(key));
}
//第二组: 把所有的values取出
Collection values = map.values();
//这里可以使用所有的Collections使用的遍历方法
//(1) 增强for
System.out.println("---取出所有的value 增强for----");
for (Object value : values) {
System.out.println(value);
}
//(2) 迭代器
System.out.println("---取出所有的value 迭代器----");
Iterator iterator2 = values.iterator();
while (iterator2.hasNext()) {
Object value = iterator2.next();
System.out.println(value);
}
//第三组: 通过EntrySet 来获取 k-v
Set entrySet = map.entrySet();// EntrySet<Map.Entry<K,V>>
//(1) 增强for
System.out.println("----使用EntrySet 的 for增强(第3种)----");
for (Object entry : entrySet) {
//将entry 转成 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
//(2) 迭代器
System.out.println("----使用EntrySet 的 迭代器(第4种)----");
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {
Object entry = iterator3.next();
//System.out.println(next.getClass());//HashMap$Node -实现-> Map.Entry (getKey,getValue)
//向下转型 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
}
}
(1)HashMap
HashMap注意事项:
- Map接口的常用实现类:HashMap、Hashtable和Properties
- HashMap是Map接口使用频率最高的实现类
- HashMap是以key-value对的方式存储数据
- key不能重复,但是value可以重复,允许使用null键和null值
- 如果添加相同的key,则会覆盖原来的key-value,等同于修改(key不会替换,val会替换)
- 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的
- HashMap没有实现同步,因此线程是不安全的
(2)Hashtable
Hashtable的使用:
- 存放的元素是键值对:即K-V
- Hashtable的键和值都不能为null,否则会抛出NullPointerException
- Hashtable使用方法基本上和HashMap一致
- Hashtable是线程安全的(synchronized),HashMap是线程不安全的
(3)Properties
Properties基本使用:
- Properties类继承自Hashtable类并且实现了Map接口,也是一种键值对的形式来保存数据
- 使用特点和Hashtable类似
- Properties还有可以用于从xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改
- xxx.properties文件通常作为配置文件,这个知识点配合IO流加以应用
(4)集合选型规则
在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行选择:
- 先判断存储数据的类型:一组对象/一组键值对
- 一组对象:Collection接口
- 允许重复:List接口
- 增删多:LinkedList【底层维护了双向链表】
- 改查多:ArrayList【底层维护了Object类型的可变数组】
- 不允许重复:Set接口
- 无序:HashSet【底层是HashMap,维护了一个hash表(数组+链表+红黑树)】
- 排序:TreeSet
- 插入和取出的顺序一致:LinkedHashSet【底层维护了数组+双向链表】
- 允许重复:List接口
- 一组键值对:Map接口
- 键无序:HashMap【底层:哈希表 jdk7:数组+链表 jdk8:数组+链表+红黑树】
- 键排序:TreeMap
- 键插入和取出的顺序一致:LinkedHashMap
- 读取文件:Properties
四、Collections工具类
(1)Collection工具类基本介绍:
- Collections是一个操作Set、List和Map等集合的工具类
- Collections中提供了一系列静态方法对集合元素进行排序、查询和修改等操作
(2)排序操作:(均为static方法)
- reverse(List):反转List中元素的顺序
- shuffle(List):对List集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定List集合元素按升序排序
- sort(List, Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
- swap(List, int, int):将指定list中i处元素和j处元素进行交换
(3)查找、替换
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object max(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
- Object min(Collection):
- Object min(Collection, Comparator):
- int frequency(Collection, Object):返回指定集合中指定元素的出现次数
- void copy(List dest, List src):将src中的内容复制到dest中
- Boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换旧值
import java.util.*;
@SuppressWarnings({"all"})
public class Main {
public static void main(String[] args) {
//创建ArrayList 集合,用于测试.
List list = new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
list.add("tom");
// reverse(List):反转 List 中元素的顺序
Collections.reverse(list);
System.out.println("list=" + list);
// shuffle(List):对 List 集合元素进行随机排序
// for (int i = 0; i < 5; i++) {
// Collections.shuffle(list);
// System.out.println("list=" + list);
// }
// sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
Collections.sort(list);
System.out.println("自然排序后");
System.out.println("list=" + list);
// sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
//我们希望按照 字符串的长度大小排序
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//可以加入校验代码.
return ((String) o2).length() - ((String) o1).length();
}
});
System.out.println("字符串长度大小排序=" + list);
// swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
//比如
Collections.swap(list, 0, 1);
System.out.println("交换后的情况");
System.out.println("list=" + list);
//Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
System.out.println("自然顺序最大元素=" + Collections.max(list));
//Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
//比如,我们要返回长度最大的元素
Object maxObject = Collections.max(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
System.out.println("长度最大的元素=" + maxObject);
//Object min(Collection)
//Object min(Collection,Comparator)
//上面的两个方法,参考max即可
//int frequency(Collection,Object):返回指定集合中指定元素的出现次数
System.out.println("tom出现的次数=" + Collections.frequency(list, "tom"));
//void copy(List dest,List src):将src中的内容复制到dest中
ArrayList dest = new ArrayList();
//为了完成一个完整拷贝,我们需要先给dest 赋值,大小和list.size()一样
for(int i = 0; i < list.size(); i++) {
dest.add("");
}
//拷贝
Collections.copy(dest, list);
System.out.println("dest=" + dest);
//boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
//如果list中,有tom 就替换成 汤姆
Collections.replaceAll(list, "tom", "汤姆");
System.out.println("list替换后=" + list);
}
}
五、课后练习
练习一
package hspCollection.homework;
import java.util.ArrayList;
/**
* Created by 此生辽阔 on 2021/7/25 21:00
*/
public class homework01 {
public static void main(String[] args) {
news news = new news("新冠确诊病例超干方,数百万印度教信徒赴恒河“圣浴”引民众担忧");
news news2 = new news("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生");
ArrayList arrayList = new ArrayList();
arrayList.add(news );
arrayList.add(news2 );
for(int i=arrayList.size();i>0;i--)
{
news obj=(news)arrayList.get(i-1);
System.out.println(obj.getTitle().substring(0,15)+"...");
}
}
}
class news{
String title;
String type;
@Override
public String toString() {
return "news{" +
"title='" + title + '\'' +
'}';
}
public news(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
练习二
package com.hspedu.homework;
import java.util.ArrayList;
import java.util.Iterator;
/**
* @author 韩顺平
* @version 1.0
*/
@SuppressWarnings({"all"})
public class Homework02 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
Car car = new Car("宝马", 400000);
Car car2 = new Car("宾利",5000000);
//1.add:添加单个元素
arrayList.add(car);
arrayList.add(car2);
System.out.println(arrayList);
//* 2.remove:删除指定元素
arrayList.remove(car);
System.out.println(arrayList);
//* 3.contains:查找元素是否存在
System.out.println(arrayList.contains(car));//F
//* 4.size:获取元素个数
System.out.println(arrayList.size());//1
//* 5.isEmpty:判断是否为空
System.out.println(arrayList.isEmpty());//F
//* 6.clear:清空
//System.out.println(arrayList.clear(););//clear是void无法打印
//* 7.addAll:添加多个元素
System.out.println(arrayList);
arrayList.addAll(arrayList);//2个宾利
System.out.println(arrayList);
//* 8.containsAll:查找多个元素是否都存在
arrayList.containsAll(arrayList);//T
//* 9.removeAll:删除多个元素
//arrayList.removeAll(arrayList); //相当于清空
//* 使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法
for (Object o : arrayList) {
System.out.println(o);//
}
System.out.println("===迭代器===");
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
}
}
/**
* 使用ArrayList 完成对 对象 Car {name, price} 的各种操作
* 1.add:添加单个元素
* 2.remove:删除指定元素
* 3.contains:查找元素是否存在
* 4.size:获取元素个数
* 5.isEmpty:判断是否为空
* 6.clear:清空
* 7.addAll:添加多个元素
* 8.containsAll:查找多个元素是否都存在
* 9.removeAll:删除多个元素
* 使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法
*/
class Car {
private String name;
private double price;
public Car(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
练习三
package hspCollection.homework;
import java.util.*;
/**
* Created by 此生辽阔 on 2021/7/25 21:18
*/
public class homework03 {
public static void main(String[] args) {
//(1)
Map<String,Integer> m= new HashMap();
m.put("jack",650);
m.put("tom",1200);
m.put("smith",2900);
//(2)
m.put("jack",2600);
//(3)
Set<String> strings = m.keySet();
for(String s:strings)
{
m.put(s,m.get(s)+100);
}
//(4)
for(String s:strings)
{
System.out.println(s);
}
//(5)
Collection<Integer> values = m.values();
Iterator<Integer> iterator ;
iterator = values.iterator();
while (iterator.hasNext()) {
Integer next = iterator.next();
System.out.println(next);
}
}
}
练习四
练习五