1. 集合概述
集合、数组都是对数据进行存储操作的结构,简称java容器
数组有些缺点:初始化后长度确定不便于扩展、数组提供的增删改查的方法少、数组存储的数据是有序且可以重复的(无序、不可重复的数据的要求不能满足)
Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组
Java 集合可分为 Collection 和 Map 两种体系:
Collection接口:单列数据,定义了存取一组对象的方法的集合
- List:元素有序、可重复的集合。ArrayList、LinkedList、Vector
- Set:元素无序、不可重复的集合。HashSet、LinkedHashSet、TreeSet
Map接口:双列数据,保存具有映射关系“key-value对”的集合。HashMap、LinkedHashMap、TreeMap、HashTable、Properties
2.Collection接口方法
常用方法1:
@Test
public void test(){
Collection coll = new ArrayList();
//1.boolean add(E e):将元素e添加到集合coll中
coll.add("AA");
coll.add(123);
coll.add(new Person(25, "wkm"));
coll.add(new Date());
//2.size():获取添加元素的个数
System.out.println(coll.size());// 4
//3.boolean addAll(Collection<? extends E> c): 将c集合中的元素添加到调用addAll的集合
Collection coll1 = new ArrayList();
coll1.add(12.34);
coll1.add(12L);
coll.addAll(coll1);
System.out.println(coll.size());//6
//4.boolean isEmpty(): 判断当前集合是否为空
System.out.println(coll.isEmpty());//false
//5.boolean contains(Object o): 判断当前集合是否存在元素o
System.out.println(coll.contains(123));//true
System.out.println(coll.contains(new String("AA")));//true
System.out.println(coll.contains(new Person(25, "wkm")));//false
//6.boolean containsAll(Collection<?> c):判断当前集合是否存在集合c
Collection coll2 = Arrays.asList("AA", 123);
System.out.println(coll.containsAll(coll2));//true
}
26行输出为true,可以判断contains调用了String重新的equals方法;
27行输出为false,是因为自定义Person类没有重写equals方法;如果重写就是true
因此,对于集合中包含的类,规定要重写equals方法
常用方法2:
@Test
public void test2(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(25, "wkm"));
coll.add(new String("ABC"));
coll.add(false);
//1.boolean remove(Object obj):通过元素的equals方法判断是否是
//要删除的那个元素。只会删除找到的第一个元素
System.out.println(coll.remove("ABC"));//true
System.out.println(coll);//[123, 456, Person{age=25, name='wkm'}, false]
//2.boolean removeAll(Collection coll):取当前集合的差集
Collection coll1 = Arrays.asList(123, 4567);
coll.removeAll(coll1);
System.out.println(coll);//[456, Person{age=25, name='wkm'}, false]
//3.boolean retainAll(Collection c):把交集的结果存在当前集合中,不影响c
Collection coll2 = Arrays.asList(123, 456, 789);
coll.retainAll(coll2);
System.out.println(coll);//[456]
//4.boolean equals(Object obj):当前集合和形参集合是否相等
Collection coll3 = Arrays.asList(456);
System.out.println(coll.equals(coll3));//true
}
常用方法3:
@Test
public void test3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(25, "wkm"));
coll.add(new String("ABC"));
coll.add(false);
//1.hashCode():获取集合对象的哈希值
System.out.println(coll.hashCode());//1411494710
//2.Object[] toArray():转成对象数组
Object[] arr = coll.toArray();
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
//123
//456
//Person{age=25, name='wkm'}
//ABC
//false
}
//对象数组——>集合:Array.asList
List<String> strings = Arrays.asList(new String[]{"AA", "BB", "CC"});
System.out.println(strings);//[AA, BB, CC]
//注意,传入基本数据类型的数组,数组整体被识别为1个元素
List<int[]> ints = Arrays.asList(new int[]{12, 34});
System.out.println(ints);//[[I@573fd745]
//改正方法1
List ints2 = Arrays.asList(12, 34);
System.out.println(ints2);//[12, 34]
//方法2:换成包装类
List<Integer> integers = Arrays.asList(new Integer[]{12, 34});
System.out.println(integers);//[12, 34]
}
3.Iterator迭代器接口
Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
遍历操作的两个方法:hasNext()/next()
hasNext():判断是否还有下一个元素(初始化迭代器对象时,指针在第一个元素之前)
next():先将指针下移;返回下移后指针指向的集合位置的元素
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(18, "wkm"));
coll.add(new String("adb"));
coll.add(false);
//iterator():返回迭代器对象,用于集合遍历
Iterator iterator = coll.iterator(); //coll就是被迭代的集合
System.out.println(iterator.hasNext());//true
System.out.println(iterator.next());//123
System.out.println(iterator.next());//456
System.out.println(iterator.next());//Person{age=18, name='wkm'}
System.out.println(iterator.next());//adb
System.out.println(iterator.next());//false
System.out.println(iterator.hasNext());//false:代表没有此迭代器对象没有元素
最推荐的代码编写方式:hasNext()和next()搭配使用
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(18, "wkm"));
coll.add(new String("adb"));
coll.add(false);
//iterator():返回迭代器对象,用于集合遍历
Iterator iterator = coll.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
remove
@Test
public void test2(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(18, "wkm"));
coll.add(new String("adb"));
coll.add(false);
Iterator iterator = coll.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
if(obj.equals("adb")){
iterator.remove();
//移除“adb”
}
}
//重新申请全新的迭代器对象,遍历集合查看是否移除“adb”
Iterator iter2 = coll.iterator();
while (iter2.hasNext()){
System.out.println(iter2.next());
}
/*123
456
Person{age=18, name='wkm'}
false*/
}
- 此处的remove()是迭代器对象的,与集合对象的remove()不同。
- 如果还未调用next()或在上一次调用 next()之后已经调用了 remove 方法,再调用remove都会报IllegalStateException。
使用foreach遍历集合/数组
@Test
public void test3(){
//遍历集合:for(遍历的元素类型 自定义的局部变量:集合对象)
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(18, "wkm"));
coll.add(new String("adb"));
coll.add(false);
for (Object obj : coll){
System.out.println(obj);
}
//遍历数组:for(遍历的元素类型 自定义的局部变量:数组对象)
int[] nums = new int[]{1, 2, 3, 4};
for(int i : nums){
System.out.println(i);
}
}
4.Collection子接口:List
List接口:存储有序、可重复的数据。包含三个实现类:
- ArrayList:List接口的主要实现类;底层是通过Object[] elementData实现;线程不安全的、效率高。
- LinkedList:底层通过双向链表实现,适合用于大量增、删操作。
- Vector:List接口的古老实现类(jdk1.0);底层是通过Object[] elementData实现;线程安全、效率低。
源码分析
1.ArrayList
jdk7:
ArrayList list = new ArrayList();
底层创建了一个长度为10的Object[]数组ElementData
list.add(11);
...
list.add(21);
扩容:默认情况下扩容为底层数组长度的1.5倍,并将原有数组的数据复制到新的数组中。
建议使用带参构造器:ArrayList list = new ArrayList(int Capacity)
jdk8中的变化:
ArrayList list = new ArrayList();
//此时并未创建长度为10的数组
//源码:private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
第一调用add后才创建了长度为10的数组,并将add的数据添加到ElementData[0];
后续的添加和扩容与jdk7一样。
2.LinkedList源码
jdk7与8中没有较大变化
LinkedList list = new LinkedList();
内部声明了Node类型的first和last属性,默认值为null;
调用list.add(xxx),添加元素的源代码:void linkLast(E e),过程相当于在链表末尾添加新节点
3.Vector
jdk7和jdk8初始化Vector对象时默认底层数组长度为10,扩容后默认为原来大小的2倍;
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位置的子集合
package com.coderwkm.java;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Wkm
* @date 2023-01-28 下午 6:32
* @description: List常用方法
*/
public class ListTest {
@Test
public void test1(){
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("Tom");
list.add(new Person(25, "wkm"));
System.out.println(list);
//[123, 456, Tom, Person{age=25, name='wkm'}]
//1.void add(int index, Object ele):在index位置插入ele元素
list.add(0, 456);
System.out.println(list);
//[456, 123, 456, Tom, Person{age=25, name='wkm'}]
//2.boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
List list1 = Arrays.asList("BBB", 11, 54);
list.addAll(3, list1);
System.out.println(list);
//[456, 123, 456, BBB, 11, 54, Tom, Person{age=25, name='wkm'}]
//3.Object get(int index):获取指定index位置的元素
System.out.println(list.get(2));//456
//4.int indexOf(Object obj):返回obj在集合中首次出现的位置
System.out.println(list.indexOf(456));//0
//5.int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
System.out.println(list.lastIndexOf(456));//2
//6.Object remove(int index):移除指定index位置的元素,并返回此元素
System.out.println(list.remove(5));//54
System.out.println(list);
//[456, 123, 456, BBB, 11, Tom, Person{age=25, name='wkm'}]
//7.Object set(int index, Object ele):设置指定index位置的元素为ele
System.out.println(list.set(0, "ABCF"));//456
System.out.println(list);
//[ABCF, 123, 456, BBB, 11, Tom, Person{age=25, name='wkm'}]
//8.List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
System.out.println(list.subList(3, 5));//[BBB, 11]
}
}
- 关于方法4、5, 如果obj在集合中未找到,返回-1(java中很多方法都是如此)
- 注意方法6:remove(),是移除指定索引的元素,并且返回被移除的元素;Collection接口的^ 1
- 方法7:是用ele替换index处的值,返回的也是被替换的原始值
- 方法8:左闭右开
list常用方法:
- 增:add()/addAll()/add(int index, Object ele)
- 删:remove(int index)/remove(Object obj)
- 改:set(int index, Object ele)
- 查:get(int index)
- 长度:size()
- 遍历:迭代器循环/foreach/普通的for循环
5.Collection子接口:Set
Set接口:存储无序、不可重复的数据。包括:
- HashSet:Set的主要实现类;线程不安全;可以存储null
- LinkedHashSet:HashSet子类,遍历内部数据时可以按照添加的顺序遍历;
- TreeSet:可以按照添加对象的属性进行排序
1.HashSet
以HashSet为例说明Set接口的无序、不可重复的特点:
package com.settest.java;
import org.junit.Test;
import java.util.HashSet;
import java.util.Iterator;
/**
* @author Wkm
* @date 2023-01-29 下午 11:18
* @description: 理解Set的无序、不可重复特性
*
* 无序:添加的元素在底层数组的存储顺序是按照元素的Hash值存储
* 不可重复:相同的元素只能添加一个(相同:equals的返回值是true)
*/
public class SetTest {
@Test
public void test1(){
HashSet set = new HashSet();
set.add(123);
set.add(456);
set.add("AA");
set.add("BB");
set.add(new User("wkm", 25));
set.add(new User("wkm", 25));
set.add(123);
/*
1.无序:不是按照添加的顺序显示的
AA BB User{name='wkm', age=25} 456 123
2.不可重复:
添加了两个123,但只显示1个;
未重写equals和hashCode之前,显示两个User对象;重写后只显示一个
*/
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
以HashSet为例说明添加元素的过程:
- 当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值,通过某种散列函数决定该对象在 HashSet 底层数组中的存储位置。
- 如果两个元素的hashCode()值相等,会再继续调用equals方法,如果equals方法结果 为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了, 那么会通过链表的方式继续链接(jdk7新元素添加数组中并指向旧元素,jdk8相反,即“七上八下”)。
- 如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
总结:先hashCode再equals!
关于Set需要注意:
- Set接口没有新定义的方法,使用的都是Collection接口中的方法。
- 向Set中添加的数据,一定要在所在的类重写 hashCode() 和 equals()
- 重写的 hashCode() 和 equals() 尽可能保持一致性:相等的对象(equals() 方法比较返回 true)必须具有相等的散列码 (hashCode()方法的返回值)
- 对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
package com.settest.java;
/**
* @author Wkm
* @date 2023-01-29 下午 11:51
* @description: 自定义User(用于添加到Set)
*/
public class User {
private String name;
private int age;
//构造器、get、set.....
//idea重写:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
return name != null ? name.equals(user.name) : user.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
2.LinkedHashSet
@Test
public void test2(){
/*
输出结果是按添加的顺序显示:123 456 AA BB User{name='wkm', age=25}
LinkedHashSet是HashSet的子类,在添加数据的同时维护了两个引用记录添加顺序;
因此,对于频繁遍历的操作,效率高于HashSet
*/
Set set = new LinkedHashSet();
set.add(123);
set.add(456);
set.add("AA");
set.add("BB");
set.add(new User("wkm", 25));
set.add(new User("wkm", 25));
set.add(123);
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
3.TreeSet
TreeSet:可以按照添加对象的属性进行排序,因此添加的元素不可以是不同类的对象
TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。
TreeSet底层使用红黑树结构存储数据 。新增的方法如下: (了解)
-
Comparator comparator()
-
Object first()
-
Object last()
-
Object lower(Object e)
-
Object higher(Object e)
-
SortedSet subSet(fromElement, toElement)
-
SortedSet headSet(toElement)
-
SortedSet tailSet(fromElement)
TreeSet 两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
package com.settest.java;
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/**
* @author Wkm
* @date 2023-01-30 下午 4:43
* @description: TreeSetTest
* 对于TreeSet:
* 1. 添加到数据,必须是相同类的数据
* 2. 用到先前的两种排序方式:自然排序/定制排序
* 3. 自然排序中,比较两个对象是否相等的依据:compareTo()是否返回0。而非equals()
*/
public class TreeSetTest {
//1.自然排序测试
@Test
public void test1(){
TreeSet set = new TreeSet();
set.add(new User("wkm", 25));
set.add(new User("yyy", 25));
set.add(new User("mm", 0));
set.add(new User("mm", 1));
set.add(new User("wy", 5));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
/*
1.如果没有实现某种排序:
java.lang.ClassCastException: com.settest.java.User cannot be cast to java.lang.Comparable
2.如果在compareTo中只按照name属性排序,此例中有两个name相同的对象mm但age不一样
输出结果:
User{name='mm', age=0}
User{name='wkm', age=25}
User{name='wy', age=5}
User{name='yyy', age=25}
3.在排序name的基础上再对aga进行排序:
User{name='mm', age=0}
User{name='mm', age=1}
User{name='wkm', age=25}
User{name='wy', age=5}
User{name='yyy', age=25}
*/
}
//2.定制排序测试
@Test
public void test2(){
//step1:创建comparator对象
Comparator com = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User user1 = (User)o1;
User user2 = (User)o2;
//按年龄排序
int compareValue = Integer.compare(user1.getAge(), user2.getAge());
if(compareValue != 0){
return compareValue;
}
return user1.getName().compareTo(user2.getName());
}
throw new RuntimeException("比较的对象类型不匹配");
}
};
//step2:将step1中的Comparator对象传入TreeSet带参构造器(先前是传入sort方法)
TreeSet set = new TreeSet(com);
set.add(new User("wkm", 25));
set.add(new User("yyy", 25));
set.add(new User("mm", 0));
set.add(new User("mm", 1));
set.add(new User("wy", 5));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
/*
User{name='mm', age=0}
User{name='mm', age=1}
User{name='wy', age=5}
User{name='wkm', age=25}
User{name='yyy', age=25}
*/
}
}
//关于User类的自然排序
package com.settest.java;
/**
* @author Wkm
* @date 2023-01-29 下午 11:51
* @description: 自定义User(用于添加到Set)
*/
public class User implements Comparable{
private String name;
private int age;
//构造器、get、set、toString、hashCode、equals...
@Override
public int compareTo(Object o) {
if(o instanceof User){
//按name排序
User user = (User)o;
int comparevalue = this.name.compareTo(user.name);
if (comparevalue != 0){
return comparevalue;
}
//再按age排序
return Integer.compare(this.age, user.age);
}
throw new RuntimeException("比较的对象类型不匹配");
}
}
6.Map接口
1.概述
Map:双列数据,存储key-value键值对
Map的分类:
- HashTable:古老实现类;线程安全、效率低;不能存储null的key和value。
- Properties:常用来处理配置文件;key和value都是String类型。
- HashMap:Map的主要实现类;线程不安全、效率高;可存储null的key和value。
- LinkedHashMap:遍历map元素时可按照添加顺序实现遍历(在HashMap底层结构基础上添加了一对记录指向前后元素的指针)。
- TreeMap:按照添加的key-value进行排序,实现排序遍历。(根据key进行自然排序/定制排序;红黑树)
关于Map结构:
- Map中的key:无序、不可重复,用Set存(XXSet与XXMap对应)。
- Map中的value:无序、可重复,用Collection存。
- Map中的entry:一个key-value构成了一个entry对象;entry对象无序、不可重复,使用Set存储所有的entry。
对于key:若是HashMap,key所在的类要重写 equals() 和 hashCode() ; 若是TreeSet,自然排序/定制排序。
对于value:value所在的类重写 equals()。
2.HashMap底层实现原理
①jdk7:
HashMap map = new HashMap();
此时,底层创建了长度为16的数组:Entry[] table
//....经过若干操作
map.put(key1, value1);
首先调用key1所在类的hashCode()(实际上是源码中的 hash(key) 方法)计算key1的hash值,此hash值经过某种算法计算( indexFor() )后,得到在Entry数组中的存放位置。
-
case1:如果此位置上的数据为空,key1-value1添加成功;
-
如果此位置上的数据不为空(此位置存有一/多个数据,以链表形式存储),比较key1和已经存在数据的hash值:
- case2:两者的hash值不同:key1-value1添加成功;
- key1的hash值和某个存在的数据(key2-value2)的hash相同:调用key1所在类的equals():key.equals(key2)
- case3:返回false: key1-value1添加成功;
- 返回true:用value替换value2;
case2和case3:key1-value1与原来的数据以链表方式存储(头插/尾插)
扩容问题:当超出threshhold值且要存放的位置非空,扩容为原始的2倍, 并将原始的数据复制过来。
②jdk8的变化
-
HashMap map = new HashMap();
此时并未直接创建长度为16的数组,而是在首次向此map中调用put时才创建。
-
jdk8的底层数组:Node[]
-
jdk7底层结构:数组+链表,jdk8是链表+数组+红黑树
几个常量:
- DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
- DEFAULT_LOAD_FACTOR:HashMap的默认加载因子,0.75
- threshold:扩容的临界值,等于容量*填充因子:16 * 0.75 = 12
- TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
- MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,64
3.LinkedHashMap
LinkedHashMap重写了父类的的 NewNode() ;
HashMap中的内部类:Node
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
LinkedHashMap中的内部类:Entry
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after; //记录添加元素的顺序
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
4.Map常用方法
package com.HashMap.java;
import org.junit.Test;
import java.util.*;
/**
* @author Wkm
* @date 2023-01-31 上午 12:04
* @description: TODO
*/
public class MapTest {
//常用方法1. 添加、删除、修改操作
@Test
public void test1(){
HashMap map = new HashMap();
//1. Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
map.put("AA", 123);
map.put("BB", 456);
map.put("CC", 789);
//根据源码,此时123被替换为456
map.put("AA", 456);
System.out.println(map);//{AA=456, BB=456, CC=789}
//2. void putAll(Map m):将m中的所有key-value对存放到当前map中
HashMap map1 = new HashMap();
map1.put(123, 456);
map1.put(456, "DD");
System.out.println("map1:"+ map1);// map1:{456=DD, 123=456}
map.putAll(map1);
System.out.println("map:" + map);// map:{AA=456, BB=456, CC=789, 456=DD, 123=456}
//3. Object remove(Object key):移除指定key的key-value对,并返回value
Object rec = map.remove(456);
System.out.println(rec);// DD
System.out.println("map:" + map);// map:{AA=456, BB=456, CC=789, 123=456}
//4. void clear():清空当前map中的所有数据
map.clear();
System.out.println(map);//{}
}
//常用方法2. 元素查询的操作:
@Test
public void test2(){
//1. Object get(Object key):获取指定key对应的value
HashMap map = new HashMap();
map.put("AA", 123);
map.put("BB", 456);
map.put("CC", 789);
Object aa = map.get("AA");
System.out.println(aa);//123
System.out.println(map);//{AA=123, BB=456, CC=789}
//2. boolean containsKey(Object key):是否包含指定的key
System.out.println(map.containsKey("AA"));//true
System.out.println(map.containsKey("DD"));//false
//3. boolean containsValue(Object value):是否包含指定的value
System.out.println(map.containsValue("789"));//false
System.out.println(map.containsValue(789));//true
//4. int size():返回map中key-value对的个数
System.out.println(map.size());// 3
//5. boolean isEmpty():判断当前map是否为空
System.out.println(new HashMap().isEmpty());//true
System.out.println(map.isEmpty());// false
//6. boolean equals(Object obj):判断当前map和参数对象obj是否相等
HashMap map2 = new HashMap();
map2.put("AA", 123);
map2.put("BB", 456);
System.out.println(map.equals(map2));//false
map2.put("CC", 789);
System.out.println(map.equals(map2));//true
}
@Test
public void test3(){
//1. Set keySet():返回所有key构成的Set集合
HashMap map = new HashMap();
map.put("AA", 123);
map.put("BB", 456);
map.put("CC", 789);
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
// AA
// BB
// CC
}
//2. Collection values():返回所有value构成的Collection集合
Collection values = map.values();
for(Object obj : values){
System.out.println(obj);
/*
123
456
789
!!!可以看到通过方法1和方法2遍历的key和value的顺序是一一对应的
*/
}
//3. Set entrySet():返回所有key-value对构成的Set集合
Set set1 = map.entrySet();
Iterator iterator1 = set1.iterator();
while (iterator1.hasNext()){
//将entrySet()获得的元素墙砖成Map中的Entry
Map.Entry entry = (Map.Entry)iterator1.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
/*
AA--->123
BB--->456
CC--->789
!!还可以通过前两个方法先获取keySet,再通过get(Object key)取value
*/
}
}
}
5.TreeMap
与TreeSet类似,需要注意:
- 添加的key必须是同一个类创建的对象。
- 按key排序:自然排序/定制排序。
package com.HashMap.java;
import org.junit.Test;
import java.util.*;
/**
* @author Wkm
* @date 2023-01-31 下午 9:06
* @description: 此处添加的User自定义类与TreeSet测试的User类相同
*/
public class TreeSetTest {
//自然排序
@Test
public void test1(){
TreeMap treeMap = new TreeMap();
treeMap.put(new User("wkm", 25), 93);
treeMap.put(new User("yyy", 24), 95);
treeMap.put(new User("mm", 0), 99);
treeMap.put(new User("wy", 1), 100);
Set set1 = treeMap.entrySet();
Iterator iterator1 = set1.iterator();
while (iterator1.hasNext()){
Map.Entry entry = (Map.Entry)iterator1.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
/*
User{name='mm', age=0}--->99
User{name='wkm', age=25}--->93
User{name='wy', age=1}--->100
User{name='yyy', age=24}--->95
*/
}
//定制排序
@Test
public void test2(){
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return Integer.compare(u1.getAge(), u2.getAge());
}
throw new RuntimeException("比较的对象类型不匹配");
}
});
treeMap.put(new User("mm", 0), 99);
treeMap.put(new User("wkm", 25), 93);
treeMap.put(new User("yyy", 24), 95);
treeMap.put(new User("wy", 1), 100);
Set set1 = treeMap.entrySet();
Iterator iterator1 = set1.iterator();
while (iterator1.hasNext()){
Map.Entry entry = (Map.Entry)iterator1.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
/*
User{name='mm', age=0}--->99
User{name='wy', age=1}--->100
User{name='yyy', age=24}--->95
User{name='wkm', age=25}--->93
*/
}
}
6.Properties
- Properties 类是 Hashtable 的子类,该对象用于处理属性文件
- 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
- 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法
package com.HashMap.java;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
properties.load(fileInputStream);//加载流对应的文件
String name = properties.getProperty("user");
String password = properties.getProperty("password");
System.out.println("user: " + name + ", password: " + password);
//user: wkm王杨, password: 123wkm
}
}
注意几点:
-
在idea工程中创建properties文件:右键工程名称——>New,如下图所示:
如果创建File,需要自动补全文件后缀**.properties**
-
properties文件内容如下:
user=wkm王杨 password=123wkm
注意”=“与字符之间不要保留空格!
-
测试代码输出的乱码问题
7.Collections工具类
package com.HashMap.java;
import com.HashMap.exer.test1;
import org.junit.Test;
import java.util.*;
/**
* @author Wkm
* @date 2023-01-31 下午 9:52
* @description: Collections常用方法测试
*
* 一、排序操作:(均为static方法)
* reverse(List):反转 List 中元素的顺序
* shuffle(List):对 List 集合元素进行随机排序
* sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
* sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
* swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
*
* 二、查找、替换:
* 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):使用新值替换List对象的所有旧值
*/
public class CollectionsTest {
//一、排序操作:(均为static方法)
@Test
public void test1(){
ArrayList list = new ArrayList();
list.add(5);
list.add(6);
list.add(7);
//1. reverse(List):反转 List 中元素的顺序
Collections.reverse(list);
System.out.println(list);//[7, 6, 5]
//2. shuffle(List):对 List 集合元素进行随机排序
Collections.shuffle(list);
System.out.println(list);//[6, 5, 7]
//3. sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
list.add(3);
Collections.sort(list);
System.out.println(list);//[3, 5, 6, 7]
//4. sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
Comparator com = new Comparator(){
@Override
public int compare(Object o1, Object o2) {
//逆序
int num1 = (Integer)o1;
int num2 = (Integer)o2;
return num2 > num1 ? 1 : -1;
}
};
Collections.sort(list, com);
System.out.println(list);//[7, 6, 5, 3]
//5. swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
Collections.swap(list, 0, 2);
System.out.println(list);//[5, 6, 7, 3]
}
//二、查找、替换:
@Test
public void test2(){
//1. Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
ArrayList list = new ArrayList();
list.add(5);
list.add(6);
list.add(7);
System.out.println(Collections.max(list));// 7
//2. Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
Comparator com = new Comparator(){
@Override
public int compare(Object o1, Object o2) {
//逆序
int num1 = (Integer)o1;
int num2 = (Integer)o2;
return num2 > num1 ? 1 : -1;
}
};
System.out.println(Collections.max(list, com));// 5
//3. Object min(Collection)
//4. Object min(Collection,Comparator)
//5. int frequency(Collection,Object):返回指定集合中指定元素的出现次数
list.add(5);
list.add(0);
System.out.println(Collections.frequency(list, 5));// 2
System.out.println(list);//[5, 6, 7, 5, 0]
//6. void copy(List dest,List src):将src中的内容复制到dest中
//注意下一行的写法技巧
List dest = Arrays.asList(new Object[list.size()]);
Collections.copy(dest, list);
System.out.println(dest);//[5, 6, 7, 5, 0]
//7. boolean replaceAll(List list,Object oldVal,Object newVal):
// 使用新值替换List对象的所有旧值
Collections.replaceAll(list, 5, 6);
System.out.println(list);//[6, 6, 7, 6, 0]
}
}
Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集 合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
Enumeration 接口是 Iterator 迭代器的 “古老版本”