1.java里,集合包含Collection(单列集合)和Map(双列集合),两者均为根接口,其下还有多个实现类。关系图
1)Collection关系图
2)Map关系图
2.集合概述
package com.yl.pdfdemo.day08.p2;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
/**
* @Author wfj
* @Date 2021/6/11
* @Description 集合
* @Version 1.0
*/
public class CollectionTest {
/**
* 集合框架的概述
* 1.集合,数组都是对多个数据进行存储操作的结构,简称java容器
* 说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,jpg..)
*
*一、数组
* 2.1 数组特点
* 一旦初始化以后,其长度就确定了
* 数组一旦定义好,其元素的的类型也确定了,我们也就只能操作指定类型的数据了
* 比如int[] arr,String[] arrs
* 2.2 数组缺点
* 1)一旦初始化后,其长度不可修改
* 2)数组中提供的方法非常有限,对于增,删,改,查,非常不便,同时效率不高
* 3)获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
* 4)数组存储数据的特点:有序,可重复,对于无序,不可重复的需求,不能满足
*
* 二、集合框架
* Collection接口:单列集合,用来存储一个一个的对象
* --List接口:存储有序的,可重复的数据
* --ArrayList,LinkedList,Vector
*
* --Set接口:存储无序的,不可重复的数据
* --HashSet,LinkedHashSet,TreeSet
* Map接口:双列集合,用来存储一对一(key-value)一对的数据
* --HashMap,LinkedHashMap,TreeMap,HashTable,Properties
*/
@Test
public void test1() {
Collection collection = new ArrayList();
//添加元素
collection.add("a");
collection.add("b");
collection.add(123);
collection.add(new Date());
System.out.println(collection.size());//4
Collection collection2 = new ArrayList();
collection2.add("q");
collection2.add(99);
//将一个集合的所有元素添加到新集合里
collection.addAll(collection2);
System.out.println(collection.size());//6
//清空元素
collection.clear();
//判断当前集合是否为空
System.out.println(collection.isEmpty());//true
}
}
3.Collection一些常用方法
package com.yl.pdfdemo.day08.p2;
import org.junit.Test;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* @Author wfj
* @Date 2021/6/15
* @Description 集合常用方法
* @Version 1.0
*/
public class CollectionTest1 {
@Test
public void test1() {
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add("abc");
coll1.add(false);
coll1.add(new String("hello"));
Dog dog = new Dog("小白",3);
coll1.add(dog);
//contains方法,判断集合里是否包含某一个元素
//注意,如果元素为某一个对象时,对象对应的javabean最好重写equals方法
System.out.println(coll1.contains(new String("hello")));//true
System.out.println(coll1.contains(new Dog("小白",3)));//true
Collection coll2 = Arrays.asList(123, "abc");
//containsAll,判断某个集合是否包含另外一个集合的所有元素
System.out.println(coll1.containsAll(coll2));//true
}
@Test
public void test2() {
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add("a");
coll1.add(true);
coll1.add(new Dog("小黑",5));
boolean isRemove = coll1.remove(123);
System.out.println(isRemove);//true
//Dog要重写equals方法
boolean isRemove2 = coll1.remove(new Dog("小黑", 5));
System.out.println(isRemove2);//true
System.out.println(coll1.toString());//[a, true]
//removeAll()从当前集合中移除另外一个集合中的所有元素
Collection coll2 = new ArrayList();
coll2.add(1);
coll2.add(2);
coll2.add("a");
coll2.add("b");
Collection coll3 = new ArrayList();
coll3.add(1);
coll3.add("b");
boolean isRemoveAll = coll2.removeAll(coll3);
System.out.println(isRemoveAll);//true
System.out.println(coll2.toString());//[2, a]
}
@Test
public void test3() {
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add("a");
coll1.add(true);
coll1.add(new Dog("小黑",5));
Collection coll2 = Arrays.asList(123, "a");
//retainAll,求两个集合的交集,并且返回coll1
coll1.retainAll(coll2);
System.out.println(coll1.toString());//[123, a]
}
@Test
public void test4() {
//equals() 判断两个集合的元素是否全都相同
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add("a");
coll1.add(true);
coll1.add(new Dog("小黑",5));
Collection coll2 = new ArrayList();
coll1.add(123);
coll1.add("a");
coll1.add(true);
coll1.add(new Dog("小黑",5));
System.out.println(coll1.equals(coll2));//true
//获取哈希值
System.out.println(coll1.hashCode());//-851290633
//集合转数组
Object[] objects = coll1.toArray();
for (int i = 0; i <objects.length; i++) {
System.out.println(objects[i]);
}
//数组转集合
List<String> list = Arrays.asList(new String[]{"AA", "bb", "cc"});
System.out.println(list.toString());//[AA, bb, cc]
//注意:如果是基本数据类型的数组,其会把这个数组对象当作一个元素
List arr1 = Arrays.asList(new int[]{11,22});
System.out.println(arr1.size());//1
List arr2 = Arrays.asList(new Integer[]{11,22,33});
System.out.println(arr2.size());//3
}
}
4.List接口详解
package com.yl.pdfdemo.day08.p2;
import org.junit.Test;
import org.omg.PortableServer.LIFESPAN_POLICY_ID;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author wfj
* @Date 2021/6/15
* @Description List接口
* @Version 1.0
*/
public class ListTest {
/**
* 1.List接口:存储有序的,可重复的数据
* --ArrayList 最常用的一个实现类,线程不安全的,效率高,底层使用数组
* --LinkedList 对于频繁地使用插入,删除这些操作,使用LinkedList效率比较高(数组增加,删除元素,其他元素的位置也要变更,
* 但是如果是链表的话,直接修改几个元素的指针地址就行了),其底层使用双向链表存储
* --Vector jdk1.0发布的,线程安全的,效率低底层使用数组
*
* ArrayList,LinkedList,Vector的异同?
* 相同点:三个类都是实现了List接口,存储数据的特点相同,存储有序的,可重复的数据
* 不同点:见上
*
* 2.ArrayList的源码分析:
* 2.1 jdk7(创建ArrayList对象的方式类似于饿汉模式)
* ArrayList list = new ArrayList() //底层创建了长度是10的Object[]数组elementDate
* list.add(1);//elementData[0] = new Integer(1)
* ...
* list.add(11)//如果此次的添加导致底层elementData数组容量不够,则扩容
* 默认情况下,扩容为原来的1.5倍,同时需要将旧数组的元素赋值到新数组,所以开发中,如果
* 确定了元素的个数,建议使用带参的构造器
*
* 2.2 jdk8 (创建ArrayList对象的方式类似于懒汉模式,节省内存)
* ArrayList list = new ArrayList();//底层Object[] elementDate初始化为{},并没有创建长度为10的数组
* list.add(1); //第一个调用list时,底层才创建了长度为10的数组,并将元素添加到数组中
* 其他无异
*
* 3.LinkedList的源码分析:
* LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,属性值为null
* list.add(1); //将1封装到Node中,创建了Node对象
*
* Node的定义,体现了LinkedList双向链表的说话
* private static class Node<E> {
* E item;
* Node<E> next;
* Node<E> prev;
*
* Node(Node<E> prev, E element, Node<E> next) {
* this.item = element;
* this.next = next;
* this.prev = prev;
* }
* }
*
* 4.Vector的源码分析:
* jdk7和jdk8中通过Vector()构造器创建对象时,底层创建了长度为10的数组
* 在扩容方面,默认扩容长度为原来的2倍
*
*
*/
//List接口中常用方法
@Test
public void tes1() {
ArrayList list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);//[1, 2, 3]
//add()往指定索引位置插入元素
list.add(1,"a");
System.out.println(list);//[1, a, 2, 3]
//addAll()从指定索引位置开始将另外一个集合中所有的元素添加进来
List list1 = Arrays.asList(4,5,6);
list.addAll(1,list1);
System.out.println(list);//[1, 4, 5, 6, a, 2, 3]
//get()获取第一个元素
System.out.println(list.get(0));//1
//indexOf() 返回该元素在集合中出现的首次位置索引,如果元素不存在,则返回-1
System.out.println(list.indexOf("a"));//4
//lastIndexOf() 返回该元素在集合中出现的末尾位置索引,如果元素不存在,返回-1
System.out.println(list.lastIndexOf(2));//5
//remove() 移除指定索引位置的元素,并且返回该元素
Object obj = list.remove(2);
System.out.println(obj);//5
//set() 修改指定索引位置的元素
list.set(0,"timi");
System.out.println(list);//[timi, 4, 6, a, 2, 3]
//subList(int fromIndex,int toIndex)截取集合,返回从fromIndex开始,toIndex结束,左闭右开的子集合
//比如截取最后两个元素
List list2 = list.subList(list.size() - 2, list.size());
System.out.println(list2);//[2, 3]
}
@Test
public void test2() {
ArrayList list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
System.out.println(list);
changeList(list);
System.out.println(list);
}
private void changeList(ArrayList list) {
//默认会删除索引位置为3的元素
list.remove(3);
//如果要删除3这个元素,那么就得构造对象
//list.remove(new Integer(3));
}
}
5.Set接口详解
1)测试用到的javabean
package com.yl.pdfdemo.day08.p2;
import java.util.Objects;
/**
* @Author wfj
* @Date 2021/6/15
* @Description
* @Version 1.0
*/
public class Dog implements Comparable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Dog() {
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dog dog = (Dog) o;
return age == dog.age &&
Objects.equals(name, dog.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//按照姓名从大到小排序,再按照年龄从大到小排序
@Override
public int compareTo(Object o) {
if (o instanceof Dog) {
Dog dog = (Dog)o;
int i = -this.name.compareTo(dog.name);
if (i != 0) {
return i;
} else {
return -Integer.compare(this.age,dog.age);
}
}
return 0;
}
}
package com.yl.pdfdemo.day08.p2;
import java.util.Objects;
/**
* @Author wfj
* @Date 2021/6/16
* @Description
* @Version 1.0
*/
public class Employee implements Comparable {
private int age;
private String name;
private MyDate birthDay;
public Employee() {
}
public Employee(int age, String name, MyDate birthDay) {
this.age = age;
this.name = name;
this.birthDay = birthDay;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MyDate getBirthDay() {
return birthDay;
}
public void setBirthDay(MyDate birthDay) {
this.birthDay = birthDay;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Objects.equals(name, employee.name) &&
Objects.equals(birthDay, employee.birthDay);
}
@Override
public int hashCode() {
return Objects.hash(age, name, birthDay);
}
@Override
public String toString() {
return "Employee{" +
"age=" + age +
", name='" + name + '\'' +
", birthDay=" + birthDay +
'}';
}
//按照名字从大到小排序
@Override
public int compareTo(Object o) {
if (o instanceof Employee) {
Employee employee = (Employee)o;
return -this.name.compareTo(employee.name);
}
return -1;
}
}
package com.yl.pdfdemo.day08.p2;
/**
* @Author wfj
* @Date 2021/6/16
* @Description
* @Version 1.0
*/
public class MyDate {
private String year;
private String month;
private String day;
public MyDate() {
}
public MyDate(String year, String month, String day) {
this.year = year;
this.month = month;
this.day = day;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getMonth() {
return month;
}
public void setMonth(String month) {
this.month = month;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
@Override
public String toString() {
return "MyDate{" +
"year='" + year + '\'' +
", month='" + month + '\'' +
", day='" + day + '\'' +
'}';
}
}
- Set接口概述
package com.yl.pdfdemo.day08.p2;
import org.junit.Test;
import java.util.*;
/**
* @Author wfj
* @Date 2021/6/15
* @Description Set接口
* @Version 1.0
*/
public class SetTest {
/**
* 一、Set接口:存储无序的,不可重复的数据(它本身没有定义额外的方法,我们直接使用Collection接口的方法就行)
* --HashSet: 作为Set接口的主要实现类,线程不安全的,可以存储null值,底层使用数组+链表
* --LinkedHashSet: 作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序来遍历,
* 在往LinkedHashSet添加数据的同时,每个数据还维护了两个引用,一个指向上前一个数据,一个指向后一个数据
* 所以,对于频繁的遍历操作,LinkedHashSet的效率是比HashSet要高的,其底层使用数组+链表
*
* --TreeSet: 可以按照添加对象的指定属性,进行排序,底层使用二叉树
*
*
* 注意:
* 1.无序性:不等于随机性,存储的数据在底层数组中,并非按照数组索引来的顺序添加,而是根据数据的哈希值决定的
*
* 2.不可重复性:保证添加元素按照equals()判断时,不能返回true,即相同的元素只能添加一个
*
* 二·、添加元素的过程,以HashSet为例
* 我们向HashSet中添加元素a,首先调用元素a所在的hashCode()方法,计算元素a的哈希值
* 此哈希值接着通过某种算法计算出在HashSet底层数组中存在的位置,即索引位置,判断此位置上是否有元素
* 如果此位置上没有元素,则元素a添加成功 ==》情况一
* 如果此位置上有其他元素b(或者以链表的形式存在多个元素),则比较元素a与元素b的哈希值
* 如果哈希值不相同,则元素a添加成功 ==》 情况二
* 如果哈希值相同,进而需要调用元素a所在类的equals()方法
* equals()方法返回true,元素a添加失败
* equals()方法返回false,元素a添加成功 ==》情况三
*
* 对于情况二和情况三而言,元素a与已经存在指定索引位置上的数据以链表的方式存储
* jdk7:元素a放到数组中,指向原来的元素
* jdk8:原来的元素还是在数组中,指向元素a
* 总结:七上八下
*
* 要求:如果往Set中,添加数据,其所在的类必须要从重写hashCode()方法和equals()方法,
* 重写的hashCode()方法和equals()方法尽可能保持一致,相等的对象必须具有相等的散列码
*/
@Test
public void test1() {
Set set = new HashSet();
set.add(1);
set.add("a");
set.add(100);
set.add(66);
set.add(1);//添加了重复元素,其不会添加到集合里
set.add("b");
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next());//1 a 66 b 100
}
System.out.println();
Set set1 = new LinkedHashSet();
set1.add(1);
set1.add("a");
set1.add(100);
set1.add(66);
set1.add("b");
Iterator iterator1 = set1.iterator();
while (iterator1.hasNext()) {
//会按照添加的顺序来遍历,但是实际上并不是有序的。。。
System.out.print(iterator1.next());//1 a 100 66 b
}
}
//TreeSet
@Test
public void test2() {
/**
* 向TreeSet中添加数据,要求是相同类的对象
* 两种排序方式:自然排序(实现Comparable接口重写compareTo()方法) 定制排序(Comparator)
* 自然排序中,比较两个对象是否相等的标准为:compareTo()返回0,不再是equals()
* 定制排序中,比较两个对象是否相等的标准为:compareTo()返回0,不再是equals()
*
*
*/
TreeSet set = new TreeSet();
set.add(1);
set.add(-1);
set.add(11);
set.add(1111);
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("==========================");
//自然排序
TreeSet set1 = new TreeSet();
set1.add(new Dog("xi",13));
set1.add(new Dog("xing",13));
set1.add(new Dog("x",13));
set1.add(new Dog("xibao",13));
set1.add(new Dog("xibao",19));
Iterator iterator1 = set1.iterator();
while (iterator1.hasNext()) {
System.out.println(iterator1.next());
}
System.out.println("==========================");
//定制排序
TreeSet set2 = new TreeSet(new Comparator() {
//按照年龄从大到小排序,姓名从小到大排序
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Dog && o2 instanceof Dog) {
Dog d1 = (Dog)o1;
Dog d2 = (Dog)o2;
int i = -Integer.compare(d1.getAge(), d2.getAge());
if (i != 0) {
return i;
} else {
return d1.getName().compareTo(d2.getName());
}
}
return -1;
}
});
set2.add(new Dog("xi",13));
set2.add(new Dog("xing",13));
set2.add(new Dog("x",13));
set2.add(new Dog("xibao",13));
set2.add(new Dog("xibao",19));
Iterator iterator2 = set2.iterator();
while (iterator2.hasNext()) {
System.out.println(iterator2.next());
}
}
//面试题
@Test
public void test3() {
HashSet set = new HashSet();
Dog dog1 = new Dog("小白",13);
Dog dog2 = new Dog("小兰",15);
set.add(dog1);
set.add(dog2);
System.out.println(set);//[Dog{name='小白', age=13}, Dog{name='小兰', age=15}]
dog1.setName("小黑");
set.remove(dog1);//注意,这里删除的索引位置来源(name为小黑,age为13的哈希值,数组中没有这个索引位置,所以什么都没删除到)
System.out.println(set);//[Dog{name='小黑', age=13}, Dog{name='小兰', age=15}]
set.add(new Dog("小黑",13));//[Dog{name='小黑', age=13}, Dog{name='小黑', age=13}, Dog{name='小兰', age=15}]
System.out.println(set);
set.add(new Dog("小白",13));//[Dog{name='小黑', age=13}, Dog{name='小黑', age=13}, Dog{name='小白', age=13}, Dog{name='小兰', age=15}]
System.out.println(set);
}
}
3)练习
package com.yl.pdfdemo.day08.p2;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/**
* @Author wfj
* @Date 2021/6/16
* @Description TreeSet练习
* @Version 1.0
*/
public class ExceTest {
public static void main(String[] args) {
Employee employee = new Employee(17,"bin",new MyDate("2020","10","11"));
Employee employee1 = new Employee(11,"ain",new MyDate("2020","10","11"));
Employee employee2 = new Employee(19,"lin",new MyDate("2020","10","11"));
Employee employee3 = new Employee(7,"cin",new MyDate("2020","10","11"));
TreeSet set = new TreeSet();
set.add(employee);
set.add(employee1);
set.add(employee2);
set.add(employee3);
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("=============");
//定制排序
TreeSet set1 = new TreeSet(new Comparator() {
//按照年龄从大到小排序
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Employee && o2 instanceof Employee) {
Employee e1 = (Employee)o1;
Employee e2 = (Employee)o2;
return -Integer.compare(e1.getAge(),e2.getAge());
}
return -1;
}
});
set1.add(employee);
set1.add(employee1);
set1.add(employee2);
set1.add(employee3);
Iterator iterator1 = set1.iterator();
while(iterator1.hasNext()) {
System.out.println(iterator1.next());
}
}
}
6.集合的遍历,使用迭代器
package com.yl.pdfdemo.day08.p2;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* @Author wfj
* @Date 2021/6/15
* @Description 集合元素的遍历操作,使用迭代器接口
* @Version 1.0
*/
public class IteratorTest {
@Test
public void test1() {
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add(7);
coll1.add(10);
coll1.add("a");
coll1.add(true);
Iterator iterator = coll1.iterator();
//hasNext(),判断是否还有下一个元素
while (iterator.hasNext()) {
//next(),取下一个元素的值
System.out.print(iterator.next());//123710atrue
}
}
/**
* remove方法,移除元素去
*/
@Test
public void test2() {
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add(7);
coll1.add(10);
coll1.add("a");
coll1.add(true);
Iterator iterator = coll1.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if ("a".equals(obj)) {
iterator.remove();
}
}
//这里要重新赋值迭代器
iterator = coll1.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
7.Map接口详解
package com.yl.pdfdemo.day08.p2;
import org.junit.Test;
import java.io.FileInputStream;
import java.util.*;
/**
* @Author wfj
* @Date 2021/6/16
* @Description Map
* @Version 1.0
*/
public class MapTest {
/**
* 一、Map: 双列数据,存储key-value对的数据
* --HashMap: 作为Map的主要实现类,jdk1.2出现,线程不安全的,效率高,可以存储null的key和value
* -- LinkedHashMap:保证在遍历map元素时,可以按照添加元素时的顺序来遍历
* 原因:在原有的HashMap底层结构基础上,添加了一对指针,分别指向前一个元素和后一个元素,
* 对于频繁的遍历操作,LinkedHashMap比HashMap效率高
* --TreeMap:保证按照添加的key-value对进行排序,实现排序遍历,此时考虑key的自然排序或者定制排序,底层使用红黑树
* --HashTable: 古老的实现类,jdk1.0出现,线程安全的,效率低,不可以存储null的key和value
* --Properties:常用来处理配置文件,key和value都是String类型
*
*
* HashMap的底层:数组+链表(jdk7及之前)
* 数组+链表+红黑树(jdk8)
*
* 面试题:
* 1.HashMap的底层实现原理?
* 2.HashMap和HashTable异同?
* 3.CurrentHashMap和HashTable的异同?
*
* 二、Map结构的理解
* Map中的key:无序,不可重复的,使用Set存储所有的key ==> key所在的类要重写hasCode()方法和equals()方法
* Map中的value:无序,可重复的,使用Collection存储所有的value ==》 value所在的类要重写equals()方法
* 一个键值对:key-value构成了一个Entry对象
* Map中的entry: 无序,不可重复的,使用Set存储所有entry
*
* 三、HashMap的底层原理(重点),以jdk7说
* HashMap map = new HashMap()
* 在实例化以后,底层创建了长度为16的一维数组Entry[] table
* 执行多次put操作
* map.put(key1,value1)
* 首先调用key1所在的类的hashCode()方法计算key1的哈希值,此哈希值通过某种算法计算后,得到在Entry数组中存在的位置
* 如果此位置上数据为空,此时的key1-values1则添加成功 ==情况一
* 如果此位置上的数据不为空,(意味着此位置原本已存在一个或者多个数据(以链表方式存在)),比较key1和已存在的一个或多个数据的哈希值:
* 如果key1的哈希值与已存在的数据的哈希值不相同,则key1-value1添加成功 ==情况二
* 如果key1的哈希值与已存在的某一个数据(key2-value2)的哈希值相同,继续比较,调用key1所在类中的equals(key2)
* 如果equals()返回false,此时key1-value1添加成功 ==情况三
* 如果equals()返回true,使用value1替代value2
*
* 补充:关于情况二和情况三,此时key1-value1和原来的数据以链表的方法存储
* 在不断的添加过程中,会涉及到扩容的问题,当超出临界值(且要存放的位置非空)时,要扩容,默认的扩容方式:扩容为原来容量的两倍,并将原来的数据复制过来
*
* jdk8相对于jdk7在底层方面的不同
* 1.new HashMap():底层没有数组
* 2.jdk8底层的数组四Node[],非Entry[]
* 3.首次调用put时,底层创建长度为16的数组
* 4.jdk7中底层结构只有:数组+链表,jdk8中底层结构:数组+链表+红黑树
* 当数组中的某一个位置上以链表形式存储的数据个数 > 8,且当前数组长度 > 64 时
* 此时此索引位置上的所有数据改为红黑树存储
*
* DEFAULT_INITIAL_CAPACITY: HashMap的默认容量:16
* DEFAULT_LOAD_FACTOR: Hash默认的加载因子:0.75,与数组利用率有关,太小的话,数组的利用率太低,太大的话,链表就可能过多了。
* TREEIFY_THRESHOLD: 当链表中数据大于改默认值,则转换为红黑树,值为8
* MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
* threshold:扩容的临界值,等于容量 * 填充因子:16 * 0.75 =12
*
* 四、LinkedHashMap的底层实现原理,了解就好
* 能够按照添加的顺序来遍历数据,和LinkedHashSet原理一样
* 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);
* }
* }
*
*
*
*/
//基操
@Test
public void test1() {
Map map = new HashMap();
map.put(null,123);
map.put("a","java");
map.put("b","buso");
map.put("c","c++");
System.out.println(map);//{null=123, a=java, b=buso, c=c++}
Map map1 = new LinkedHashMap();
map1.put(null,123);
map1.put("a","java");
map1.put("b","buso");
map1.put("c","c++");
System.out.println(map1);//{null=123, a=java, b=buso, c=c++}
}
//map的一些常用方法
@Test
public void test2() {
Map map = new HashMap();
//put(),存数据
//新增
map.put("a",123);
map.put(12,"c");
map.put("b",5);
//修改
map.put("a",56);
System.out.println(map);//{a=56, b=5, 12=c}
//putAll(Map map)将一个map的全部数据存到另一个map里去
Map map1 = new HashMap();
map1.put("c",7);
map1.put("d",8);
map.putAll(map1);//{a=56, b=5, c=7, d=8, 12=c}
System.out.println(map);
//remove(Object key) 移除指定key对应的数据,并且返回数据
Object value = map.remove("d");
System.out.println(value);//8
System.out.println(map);//{a=56, b=5, c=7, 12=c}
//Object get(Object key) //获取指定key对应的value
Object c = map.get("c");
System.out.println(c);//7
//boolean containsKey(Object key) 是否包含指定的key
System.out.println(map.containsKey("d"));//true
//boolean containsValue(Object value) 是否包含指定的value
System.out.println(map.containsValue(8));//true
//boolean isEmpty() 判断map的长度是否为0
System.out.println(map.isEmpty());//false
//获取map中key-value对的个数
System.out.println(map.size());//4
// boolean equals(Map map) 判断两个map的key和value是否完全一致
System.out.println(map.equals(map1));//false
//clear()清空数据
map.clear();
System.out.println(map);//{}
}
//map的遍历操作
@Test
public void test3() {
Map map = new HashMap();
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",4);
map.put("e",5);
//遍历所有的key
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//遍历所有的value
Collection values = map.values();
for (Object obj : values) {
System.out.println(obj);
}
//遍历所有的key和value
//方式一:
Set entrySet = map.entrySet();
for (Object object : entrySet) {
Map.Entry entry = (Map.Entry)object;
System.out.println("键:"+entry.getKey() + "值:"+entry.getValue());
}
//方式二:
Set keySet = map.keySet();
Iterator iterator1 = keySet.iterator();
while (iterator1.hasNext()) {
Object next = iterator1.next();
Object o = map.get(next);
System.out.println("键:"+next+"值:"+o);
}
}
//TreeMap的使用
@Test
public void test4() {
//自然排序
TreeMap map1 = new TreeMap();
map1.put(new Dog("xi",13),71);
map1.put(new Dog("bai",19),70);
map1.put(new Dog("kai",10),78);
map1.put(new Dog("tian",12),90);
map1.put(new Dog("adan",11),100);
Set keySet = map1.keySet();
Iterator iterator1 = keySet.iterator();
while (iterator1.hasNext()) {
Object next = iterator1.next();
Object o = map1.get(next);
System.out.println("键:"+next+"值:"+o);
}
System.out.println("===================");
//定制排序
TreeMap map2 = new TreeMap(new Comparator() {
//按照年龄从大到小排序
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Dog && o2 instanceof Dog) {
Dog d1 = (Dog) o1;
Dog d2 = (Dog) o2;
return -Integer.compare(d1.getAge(),d2.getAge());
}
return 0;
}
});
map2.put(new Dog("xi",13),71);
map2.put(new Dog("bai",19),70);
map2.put(new Dog("kai",10),78);
map2.put(new Dog("tian",12),90);
map2.put(new Dog("adan",11),100);
Set keySet1 = map2.keySet();
Iterator iterator2 = keySet1.iterator();
while (iterator2.hasNext()) {
Object next = iterator2.next();
Object o = map2.get(next);
System.out.println("键:"+next+"值:"+o);
}
}
//Properties的使用,常用来处理配置文件,key,value都是String类型
@Test
public void test5() throws Exception{
Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("D://jdbc.properties");
properties.load(fileInputStream);//加载流对应的文件
String userName = properties.getProperty("userName");
String password = properties.getProperty("password");
System.out.println(userName);//root
System.out.println(password);//123456
}
}
jdbc.properties图
8.Collections工具类的常用方法
package com.yl.pdfdemo.day08.p2;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @Author wfj
* @Date 2021/6/21
* @Description Collections工具类的常用方法
* @Version 1.0
*/
public class CollectionsTest {
/**
* 面试题:Collection和Collections的区别?
* Collection是一个集合接口
* Collections是一个操作Collection,Map集合的工具类
*/
@Test
public void test1() {
List list = new ArrayList();
list.add(11);
list.add(67);
list.add(55);
list.add(100);
list.add(-10);
System.out.println(list);//[11, 67, 55, 100, -10]
//reverse()反转集合
Collections.reverse(list);
System.out.println(list);//[-10, 100, 55, 67, 11]
//shuffle()对集合进行随机排序
Collections.shuffle(list);
System.out.println(list);//[100, -10, 67, 55, 11]
//根据元素的自然排序对指定的list集合进行升序排序,也可以制定排序,传多一个comparator即可
Collections.sort(list);
System.out.println(list);//[-10, 11, 55, 67, 100]
//swap(list,int i, int j) 交换两个指定位置的元素
Collections.swap(list,0,1);
System.out.println(list);//[11, -10, 55, 67, 100]
//max(list)或者max(list,comparator) 求最大值,又或者按照制定排序求最大值
int max = (int)Collections.max(list);
System.out.println(max);//100
//min(list)或者mnx(list,comparator) 求最小值,又或者按照制定排序求最小值
int min = (int)Collections.min(list);
System.out.println(min);//-10
//frequency()求某个元素出现的次数
int frequency = Collections.frequency(list, -10);
System.out.println(frequency);//1
//copy(list dest,list src) 将src的内容复制到dest中
List dest = Arrays.asList(new Object[list.size()]);
Collections.copy(dest,list);
System.out.println(dest);//[11, -10, 55, 67, 100]
//replaceAll(list,Object oldVal,Object newVal) 使用新值替换旧值
Collections.replaceAll(list,100,-100);
System.out.println(list);//[11, -10, 55, 67, -100]
/**
* Collections类中提供了多个synchronizedXxx()方法,该方法可以将指定集合包装成线程同步的集合,
* 从而可以解决多线程并发访问集合时出现的线程安全问题
*/
//list1是线程安全的
List list1 = Collections.synchronizedList(list);
System.out.println(list1);
}
}