2022/1/8 1/9
1.数据结构:栈(先进后出)
入口和出口在同一侧
入栈5又称之为压栈
出栈又称之为弹栈
eg.入栈顺序为123,出栈顺序为321
2.数据结构:队列(先进先出)
入口和出口在集合的两侧
eg.进入队列123,出队列也是123
3.数据结构:数组
查询快:数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引可以快速查找某一个元素。
增删慢:数组的长度是固定的,我们想要增加、删除一个元素,必须创建一个新数组,把源数组的数据复制过来。
eg.删除数组中索引是3的元素
1.必须创建一个新的数组,长度是源数组的长度-1
2.把源数组的其他元素复制到新数组中
3.把新数组的地址赋值给变量
4.源数组会在内存中被销毁(垃圾回收)
4.数据结构:链表
查询慢:链表中的地址不是连续的,每次查询元素,都必须从头开始。
增删快:链表结构增加或删除一个元素,对链表整体结构没有影响。
链表中的每一个元素也称之为一个节点
双向链表中一个节点包含了一个数据域(存储数组),两个指针域(存储地址)
自己的地址 数据 下一个节点的地址
单向链表中一个节点包含一个数据域(存储数据)一个指针域(存储地址)
数据 下一个节点的地址
单向链表:链表中只有一条链子,只能找到其后继节点。
双向链表:链表中有两条链子,能够找通过链子找到其前驱节点和后继节点。
5.数据结构:红黑树
二叉树:分支不能超过两个
排序树/查找树:在二叉树的基础上,元素是有大小顺序的(左子数小,右子数大)
平衡二叉树:树种所有节点的左子树和右子树深度相差不超过1
平衡树是二叉查找树和堆合并构成的新的数据结构,所以和二叉查找树一样满足左子树<根节点<右子树。
红黑树:特点:趋近于平衡树,查询的速度非常的快,查询叶子节点最大次数和最小次数不能超过两倍
约束:1.节点可以是红色或者黑色的
2.根节点是黑色的
3.叶子节点(空节点)也是黑色的
4.每个红色的节点的子节点都是黑色的
5.任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
6.List集合
package ln.javatest.day12.demo01;
/*
java.util.list接口 extends Collection接口
list接口的特点:
1.有序的集合,存储元素和取出的元素的顺序是一致的(存储123,取出123)
2.有索引,包含了一些带索引的方法
3.允许存储重复的元素
list接口中带索引的方法(特有):
public void add(int index,E element):将指定的元素,添加到该集合中的指定位置上。
public E get(int index):返回集合中指定位置的元素。
public E remove(int index):移除列表中指定位置的元素,返回的是被移除的元素
public E set(int index,E element):用指定元素替换集合中指定位置的元素,返回值是更新前的元素
注意:
操作索引的时候,一定要防止索引越界异常
IndexOutOfBoundsException:索引越界异常,集合会报
ArrayIndexOutOfBoundsException:数组索引越界异常
StringIndexOutOfBoundsException:字符串索引越界异常
*/
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Demo01List {
public static void main(String[] args) {
//创建一个list集合对象,多态
List<String> list = new ArrayList<>();
//使用add方法添加元素
list.add("a");
list.add("b");
System.out.println(list); //[a,b] 不是地址,重写了toString方法
//在1号索引位置添加3
list.add(1,"3");
System.out.println(list); //[a, 3, b]
//移除2号索引位置的元素
String s = list.remove(2);
System.out.println("被移除的元素是:"+ s); //被移除的元素是:b
System.out.println(list); //[a, 3]
//把1号索引位置的元素替换为A
String s1 = list.set(1,"A");
System.out.println("被替换的元素是:"+ s1);
System.out.println(list); //
//list集合遍历有3种方式
//使用普通for循环遍历
for (int i = 0; i < list.size(); i++) {
String s2 = list.get(i);
System.out.println(s2);
}
//使用迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s2 = it.next();
System.out.println(s2);
}
//使用增强for
for (String s2 : list) {
System.out.println(s2);
}
}
}
7.ArrayList集合:(List接口的大小可变数组的实现)
她的底层数据结构是一个数组(数组的特点:查询快,增删慢)
这个实现不是同步的,多线程,速度快。
建议:查询的时候可以大量使用ArrayList集合,但是在增删的时候不建议使用。
8.LinkedList集合:(List接口的连接列表实现)
它的底层是一个链表(链表的特点:查询慢,增删快)
这个实现不是同步的,多线程,速度快。
建议:查询的时候不建议使用,但是在增删的时候可以大量使用LinkedList集合。
package ln.javatest.day12.demo01;
/*
java.util.LinkedList集合 implements List接口
LinkedList集合的特点:
1.底层是一个链表结构:查询慢,增删快
2.里面包含了大量操作首尾元素的方法
注意:使用LinkedList集合特有的方法,不能使用多态(多态的弊端是,看不到子类特有方法)
public void addFirst(E e):将指定元素插入此列表的开头
public void addLast(E e):将指定元素添加到此列表的结尾
public void push(E e):将指定元素推入此列表所表示的堆栈的第一个
public E getFirst():返回此列表的第一个元素
public E getLast():返回此列表的最后一个元素
public E removeFirst():溢出并返回此列表的第一个元素
public E removeLast():移除并返回此列表的最后一个元素
public E pop():从此列表所表示的堆栈处弹出弟一个元素
public boolean isEmpty():如果列表中不包含元素,则返回true
*/
import java.util.LinkedList;
public class Demo02LinkedList {
public static void main(String[] args) {
show01();
show02();
show03();
}
/*public void addFirst(E e):将指定元素插入此列表的开头
public void addLast(E e):将指定元素添加到此列表的结尾
public void push(E e):将指定元素推入此列表所表示的堆栈的第一个*/
private static void show01() {
//创建LinkedList集合对象
LinkedList<String> linked = new LinkedList<>();
//使用add方法往集合中添加元素
linked.add("a");
linked.add("b");
System.out.println(linked); //[a, b]
//addFirst
linked.addFirst("最前");
System.out.println(linked); //[最前, a, b]
//push
linked.push("推入的");
System.out.println(linked); //[推入的, 最前, a, b]
//addLast
linked.addLast("最后");
System.out.println(linked); //[推入的, 最前, a, b, 最后]
}
/*public E getFirst():返回此列表的第一个元素
public E getLast():返回此列表的最后一个元素*/
private static void show02() {
//创建LinkedList集合对象
LinkedList<String> linked1 = new LinkedList<>();
//使用add方法往集合中添加元素
linked1.add("a");
linked1.add("b");
System.out.println(linked1); //[a, b]
//linked1.clear(); 清空了下面取不到会报错
if(!linked1.isEmpty()){
String first = linked1.getFirst();
String last = linked1.getLast();
System.out.println(first); //a
System.out.println(last); //b
}
}
/*public E removeFirst():溢出并返回此列表的第一个元素
public E removeLast():移除并返回此列表的最后一个元素
public E pop():从此列表所表示的堆栈处弹出弟一个元素*/
private static void show03() {
//创建LinkedList集合对象
LinkedList<String> linked2 = new LinkedList<>();
//使用add方法往集合中添加元素
linked2.add("a");
linked2.add("b");
System.out.println(linked2); //[a, b]
String first1 = linked2.removeFirst();
System.out.println(first1); //a
System.out.println(linked2); //[b]
String last1 = linked2.removeLast();
System.out.println(last1); //b
System.out.println(linked2); //[]
//pop相当于First
/*String first2 = linked2.pop();
System.out.println(first2);
System.out.println(linked2);*/
}
}
9.Vector集合:类可以实现可增长的对象数组
和ArrayList底层一样
但它是单线程的,速度比较慢,不是多线程的所以被ArrayList取代
addElement(E ob); 将指定的组件添加到此向量的末尾,并将其大小增加1
10.set接口:一个不包含重复元素的Collection
package ln.javatest.day12.demo01;
/*
java.util.Set接口 extends Collection接口
set接口的特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
java.util.HashSet集合 implements Set接口
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4.底层是一个哈希表结构(查询速度非常的快)
*/
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Demo01Set {
public static void main(String[] args) {
//多态写法
Set<Integer> set = new HashSet<>();
//使用add添加
set.add(1);
set.add(2);
set.add(3);
set.add(1); //前面有重复1 所以只存储一个1
//使用迭代器遍历
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
Integer n = it.next();
System.out.println(n);
}
//使用增强for
for(Integer i : set){
System.out.println(i);
}
}
}
11.哈希值
package ln.javatest.day12.demo01;
public class Person {
//重写HashCode方法
@Override
public int hashCode() {
return 1;
}
}
package ln.javatest.day12.demo01;
/*
哈希值:是一个十进制的整数,有系统随机给出(就是对象的地址值,是个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
在Object类有一个方法,可以获取对象的哈希值
int hashCode():返回该对象的哈希码值
hashCode方法的源码:
public native int hashCode();
native :代表该方法调用的是本地操作系统的方法
*/
public class Demo01HashCode {
public static void main(String[] args) {
//Person类继承了Object类,所以可以使用Object类的hasCode方法
Person p1 = new Person();
int h1 = p1.hashCode();
System.out.println(h1); //1
Person p2 = new Person();
int h2 = p1.hashCode();
System.out.println(h2); //1
//对象的地址值用的是hashCode,只不过是用十六进制表示
//物理地址不相等
System.out.println(p1==p2);//false
/*
String类的哈希值
String类重写了Object类的hashCode方法
*/
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.hashCode()); //96354
System.out.println(s2.hashCode()); //96354
}
}
12.哈希表
HashSet集合存储数据的结构:哈希表
jdk1.8版本之前:哈希表 = 数组 +链表
jdk1.8版本之后:哈希表 = 数组 +链表
哈希表 = 数组 + 红黑树(提高查询的速度)
数据结构把元素进行分组,相同哈希值元素是一组,链表/红黑树把相同哈希值的元素连接到一起
哈希表的特点:速度快存储数据到集合中,先计算元素的哈希值
两个元素不同,但是哈希值相同,哈希冲突
把哈希值放入数组中,相同元素都放在哈希值下面,通过数组索引进行查询,查询快jdk1.8之后,如果链表中相同元素超过8位,那么就转成红黑树进行连接
红黑树(根 黑色,叶子节点 黑色 ,中间节点 红色)
用红黑树:提高查询的速度
13.Set集合存储数据不重复的原理
前提:重写的元素必须重写hashCode方法和equals方法
Set集合在调用add方法的时候,add方法会调用元素的hashCode方法和equals方法,判断元素是否重复。
重复的话就不存储,不重复的话,就把元素也存储到集合中,用链表链起来
14.HashSet存储自定义类型元素
package ln.javatest.day12.demo01;
import java.util.Objects;
public class Person1 {
private String name;
private int age;
@Override
public String toString() {
return "Person1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person1 person1 = (Person1) o;
return age == person1.age &&
Objects.equals(name, person1.name);
}
@Override
public int hashCode() {
return Objects.hash(name, 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 Person1(String name, int age) {
this.name = name;
this.age = age;
}
public Person1() {
}
}
package ln.javatest.day12.demo01;
/*
HashSet存储自定义类型元素
set集合保证元素唯一:
存储的元素,必须重写hashCode方法和equals方法
Getter/Setter方法里可以帮我们重写hashCode和equals方法
要求:
同名年龄的的人,视为同一人,只能存储一次
*/
import java.util.HashSet;
public class Demo01HashSetSavePerson {
public static void main(String[] args) {
//创建HashSet集合存储Person
HashSet<Person1> set = new HashSet<>();
Person1 p1 = new Person1("王嘉尔", 20);
Person1 p2 = new Person1("王嘉尔", 20);
//没有重写hashCode和equals方法,上面两个都会存入集合
//重写了所以上面两行一样的只存储一个
Person1 p3 = new Person1("王嘉尔", 22);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
}
}
15.LinkedHashSet集合
继承HashSet接口,能实现Set接口
它的特点:
底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表,用来记录元素的存储顺序,保证元素有序。
和HashSet方法一样,它和HashSet不一样在于它可以保证元素输入输出顺序一致。
16.可变参数
package ln.javatest.day12.demo01;
/*
可变参数:是JDk1.5之后出现的新特性
使用前提:
当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
使用格式:定义方法时使用
修饰符 返回值类型 方法名(数据类型...变量名){}
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组
来存储这些参数传递的参数个数,可以是0个(不传递),1,2...多个
*/
public class Demo01VarArgs {
public static void main(String[] args) {
int i = add(10,20);
System.out.println(i);
}
/*
可变参数的注意事项:
1.一个方法的参数列表,只能有一个可变参数
错误写法:private static int add(int...i,String...s){}
2.如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
错误写法:private static int add(int...arr,String s,double d){}
正确写法:private static int add(String s,double d,int...arr){}
*/
private static int add(int...arr) {
System.out.println(arr); //输出时一个地址,因为底层是一个数组
System.out.println(arr.length); //2
int sum = 0;
for (int i : arr) {
sum += i;
}
return sum;
}
}
17.Collections集合工具类的方法
package ln.javatest.day12.demo01;
//因为要用到Collects集合工具类中的方法sort实现类的排序,那么要指定根据什么来排序
//所以需要这个类实现Comparable接口,重写Comparable接口中的compareTo方法
public class Person2 implements Comparable<Person2>{ //这里因为是对Person2进行排序,所以泛型要写Person2
private String name;
private int age;
//重写排序的规则
@Override
public int compareTo(Person2 o) {
//return 0; //认为元素都是相同的
//自定义比较的规则,比较两个人的年龄(this,参数Person2)
return this.getAge() - o.getAge(); //年龄升序排序
}
@Override
public String toString() {
return "Person2{" +
"name='" + name + '\'' +
", age=" + 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 Person2(String name, int age) {
this.name = name;
this.age = age;
}
public Person2() {
}
}
package ln.javatest.day12.demo01;
public class Student {
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 Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package ln.javatest.day12.demo01;
/*
java.util.Collections是集合工具类,用来对集合进行操作。部分方法如下:
public static <T> boolean addAll(Collection<T> c,T...elements):往集合中添加一些元素。
public static void shuffle<list<?> list) :打乱集合顺序。
public static <T> void sort(list<T> list):将集合中元素按照默认规则排序。(升序)
public static <T> void sort(list<T> list,Comparator<? super T>):将集合中元素按照指定规则排序。(传一个集合,一个比较器,按照比较器里重写的compare方法来弄)
注意:
Comparator和Comparable的区别:
Comparable:自己this和别人参数比较,自己需要实现Comparable接口,重写比较的规则compareTo方法
Comparator:相当于找一个第三方的裁判,比较两个
注意:
sort方法使用前提:
被排序的集合里边存储的元素,必须实现Comparable,重写接口中的方法compareTo
Comparable接口的排序规则:
this-参数(升序)
参数-this(降序)
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Demo01Collections {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//一次性往集合中添加多个元素,相当于多个add方法
Collections.addAll(list,"b","a","c","e","f");
System.out.println(list); //[b, a, c, e, f]
Collections.shuffle(list);
System.out.println(list); //[c, a, f, e, b]
//sort方法值用在List(有序)集合中不用在Set集合(无序)中
Collections.sort(list);
System.out.println(list); //[a, b, c, e, f]
ArrayList<Person2> p = new ArrayList<>();
//Collections.addAll(Person2,"王嘉尔",10,"熊丰",20);
p.add(new Person2("王嘉尔",20));
p.add(new Person2("熊丰",20));
//上面这种情况下,用sort进行排序,有两个参数没有指定根据哪个排序,所以需要重写compareTo方法
Collections.sort(p);
System.out.println(p); //[Person2{name='王嘉尔', age=20}, Person2{name='熊丰', age=20}]
ArrayList<Integer> list1 = new ArrayList<>();
//一次性往集合中添加多个元素,相当于多个add方法
Collections.addAll(list1,1,5,9,3,6);
System.out.println(list1); //[1, 5, 9, 3, 6]
Collections.sort(list1, new Comparator<Integer>() {
//重写比较的规则
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2; //升序
}
});
System.out.println(list1); //[1, 3, 5, 6, 9]
ArrayList<Student> p1 = new ArrayList<>();
p1.add(new Student("王",27));
p1.add(new Student("熊",29));
Collections.sort(p1, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄排序
int result = o1.getAge() - o2.getAge();
//如果两个人年龄相同,再使用姓名的第一个字比较
if(result == 0){
result = o1.getName().charAt(0) - o2.getName().charAt(0);
}
return result;
}
});
System.out.println(p1); //[Student{name='王', age=27}, Student{name='熊', age=29}]
}
}
18.Map集合(接口)
package ln.javatest.day12.demo02;
/*
java.util.Map<k,v>集合
Map集合的特点:
1.Map集合是一个双列集合,Collection集合是单列集合,Map集合一个元素包含两个值(一个key,一个value)
2.Map集合中的元素,key和value的数据类型可以相同,也可以不同
3.Map集合中的元素,key是不允许重复的,value是可以重复的
4.Map集合中的元素,key和value是一一对应
java.util.HashMap<K,V>集合 implements Map<K,v>接口
HashSet集合new的就是HashMap,但是只用了其中的K,这里的K不能重复,所以HashSet中的不允许存储重复的数据;
HashMap的特点:
1.HashMap底层也是一个哈希表(数组+链表/红黑树),和HashSet一样:查询的速度非常快
2.这里HashMap还是一个无序的集合;
3.是个多线程,不同步;
java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
LinkedHashMap的特点:
1.底层是哈希表+链表,双重链表,另一个存储顺序
2.LinkedHashMap集合是一个有序的集合
*/
import java.util.HashMap;
import java.util.Map;
public class Demo01Map {
public static void main(String[] args) {
//Map接口中的常用方法
show01();
show02();
show03();
show04();
}
/*
public V put(K key,V value):把指定的键与指定的值添加到Map集合中
返回值:v
存储键值对的时候,key不重复,返回值v是null
存储键值对的时候,key重复,会使用新的value替换map中重复的value,返回被替换的value值
*/
private static void show01() {
//创建Map集合对象,多态
Map<String,String> map = new HashMap<>();
String v1 = map.put("王嘉尔","11");
System.out.println("v1:" + v1); //v1:null
String v2 = map.put("王嘉尔","22"); //v2:11
System.out.println("v2:" + v2);
System.out.println(map); //{王嘉尔=22}
}
/*
public V remove (Object key):把指定的键,所对应的键值对元素,在Map集合中删除,返回被删除元素的值
返回值:v
key存在,v返回被删除的值
key不存在,v返回null
*/
private static void show02() {
//c创建Map集合对象
Map<String,Integer> map1 = new HashMap<>();
map1.put("王嘉尔",20);
map1.put("熊丰",18);
System.out.println(map1); //{熊丰=18, 王嘉尔=20}
Integer n = map1.remove("王嘉尔");
System.out.println(n); //20
System.out.println(map1); //{熊丰=18}
Integer n1 = map1.remove("易烊千玺");
System.out.println(n1); //null
System.out.println(map1); //{熊丰=18}
}
/*
public V get(Object key):根据指定的键,获取Map集合中获取对应的值
返回值:v
key存在,返回对应的value值
key不存在,返回null
*/
private static void show03() {
Map<String,Integer> map2 = new HashMap<>();
map2.put("王嘉尔",20);
map2.put("熊丰",18);
Integer v1 = map2.get("王嘉尔");
System.out.println(v1);//20
Integer v2 = map2.get("ni");
System.out.println(v2);//null
}
/*
boolean containsKey(Object key):判断集合中是否包含指定的键。
包含返回true,不包含返回false
*/
private static void show04() {
Map<String,Integer> map3 = new HashMap<>();
map3.put("王嘉尔",20);
map3.put("熊丰",18);
boolean b1 = map3.containsKey("王嘉尔");
System.out.println(b1); //true
boolean b2 = map3.containsKey("ni");
System.out.println(b2); //true
}
}
19.Map集合遍历键找值方式
1.
package ln.javatest.day12.demo02;
/*
Map集合的第一种遍历方式:通过键找值的方式
Map集合中的方法:
Set<K> keySet() 返回此映射中包含的键的Set视图。
实现步骤:
1.使用Map集合中的方法KeySet(),把Map集合所有的key取出来,存储到一个Set集合中
2.遍历Set集合,获取Map集合中的每一个key
3.通过Map集合中的方法get(key),通过key找到value
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo02KeySet {
public static void main(String[] args) {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("王嘉尔",20);
map.put("易烊千玺",27);
map.put("王一博",29);
//1.使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
Set<String> set = map.keySet();
//2.遍历set集合,获取Map集合中的每一个key值
//使用迭代器
Iterator<String> it = set.iterator();
while(it.hasNext()){
String s = it.next();
//3.通过Map集合中的get(key),通过key找到value
Integer value = map.get(s);
System.out.println(s+","+value);
}
//使用增强for
for (String s : /*用set或者后面那个都行,这两相等*/map.keySet()) {
//3.通过Map集合中的get(key),通过key找到value
Integer value = map.get(s);
System.out.println(s+","+value);
}
}
}
2.Entry键值对对象
Map.Entry<K,V>:在Map接口中有一个内部接口Entry
作用:当Map集合一创建,那么就会在Map集合中创建一个Entry对象用来记录仪键与值(键值对对象、键与值的映射关系)eg:结婚证
package ln.javatest.day12.demo02;
/*
Map集合中的方法:
Set<Map.Entry<K,v>> entrySet() 返回此映射中包含的映射关系的Set视图
实现步骤:
1.使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
2.遍历Set集合,获取每一个Entry对象
3.使用Entry对象中的方法getKey()和getValue()获取键与值
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo03EntrySet {
public static void main(String[] args) {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("王嘉尔",20);
map.put("易烊千玺",27);
map.put("王一博",29);
//使用迭代器
//1.使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
Set<Map.Entry<String,Integer>> set = map.entrySet();
// 2.遍历Set集合,获取每一个Entry对象
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while(it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
//3.使用Entry对象中的方法getKey()和getValue()获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+","+value);
}
for (Map.Entry<String, Integer> entry : set) {
//3.使用Entry对象中的方法getKey()和getValue()获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+","+value);
}
}
}
20.HashMap存储自定义类型键值
package ln.javatest.day12.demo02;
public class Person {
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 Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
}
package ln.javatest.day12.demo02;
import java.util.Objects;
public class Person1 {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person1 person1 = (Person1) o;
return age == person1.age &&
Objects.equals(name, person1.name);
}
@Override
public int hashCode() {
return Objects.hash(name, 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 Person1(String name, int age) {
this.name = name;
this.age = age;
}
public Person1() {
}
}
package ln.javatest.day12.demo02;
/*
HashMap存储自定义类型键值
Map集合保证key是唯一的:
作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
*/
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo01HashMapSavePerson {
public static void main(String[] args) {
show01();
show02();
}
/*
HashMap存储自定义类型的键值
key:Person1类型
Person1类就必须重写hashCode和equals方法,以保证key唯一
value:String (可以重复)
*/
private static void show02() {
//创建HashMap集合
HashMap<Person1, String> map2 = new HashMap<>();
//往集合中添加元素
map2.put(new Person1("王嘉尔", 20), "北京");
map2.put(new Person1("易烊千玺", 23), "上海");
map2.put(new Person1("王嘉尔", 20), "深圳");
map2.put(new Person1("熊丰", 20), "北京");
//使用entrySet(取出多个对象)加增强for遍历Map1集合
Set<Map.Entry<Person1, String>> set1 = map2.entrySet();
for (Map.Entry<Person1, String> entry : set1) {
Person1 key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "," + value);
}
}
/*
HashMap存储自定义类型键值
key:String类型
String类重写了hashCode方法和equals方法,所以不需要我们重写,保证key的唯一
value:Person类型
value可以重复(同名同年龄的人视为同一个人)
*/
private static void show01() {
//创建HashMap集合
HashMap<String, Person> map1 = new HashMap<>();
//往集合中添加元素
map1.put("北京", new Person("王嘉尔", 20));
map1.put("上海", new Person("易烊千玺", 23));
map1.put("深圳", new Person("王嘉尔", 20));
map1.put("北京", new Person("熊丰", 20));
//使用keySet(返回key值)加增强for遍历Map集合
Set<String> set = map1.keySet();
for (String key : set) {
Person value = map1.get(key);
System.out.println(key + "," + value);
}
}
}
21.LinkedHashMap集合继承HashMap集合
底层原理:哈希表+链表(记录元素的顺序)
LinkedHashMap是个有序的集合
22.Hashtable集合
package ln.javatest.day12.demo02;
/*
java.util.Hashtable<K,V>集合 implements Map<K,v>接口
Hashtable:底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
HashMap:底层也是一歌哈希表,是一个线程不安全的集合,是多线程集合,速度快
HashMap集合(和之前学的所有集合):都可以存储null值,null键
Hashtable集合:不能存储null值,null键
Hashtable和Vector集合一样,被(HashMap,ArrayList)取代了
Hashtable的子类Properties依然活跃在历史舞台
Properties集合是唯一和IO流相结合的集合
*/
import java.util.HashMap;
import java.util.Hashtable;
public class Demo02HashTable {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
map.put(null,null);
System.out.println(map);
Hashtable<String,String> table = new Hashtable<>();
//出错table(null,null);
}
}
23.练习
package ln.javatest.day12.demo02;
/*
练习:
计算一个字符串中每个字符出现次数
分析:
1.使用Scanner获取用户输入的字符串
2.创建Map集合,key是字符串中的字符,value是字符的个数
3.遍历字符串,获取每一个字符
4.使用获取到的字符,去Map集合判断key是否存在
key存在:
通过字符(key),获取value(字符个数)
value++
put(key,value)把新的value存储到Map集合中
key不存在:
put(key,1)
5.遍历Map集合,输出结果
*/
import java.util.HashMap;
import java.util.Scanner;
public class Demo03MapTest {
public static void main(String[] args) {
// 1.使用Scanner获取用户输入的字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.next();
// 2.创建Map集合,key是字符串中的字符,value是字符的个数
HashMap<Character,Integer> map = new HashMap<>();
// 3.遍历字符串,获取每一个字符
for(Character c:str.toCharArray()){
// 4.使用获取到的字符,去Map集合判断key是否存在
if(map.containsKey(c)){
//key存在
// 通过字符(key),获取value(字符个数)
Integer value = map.get(c);
value++;
map.put(c,value);
}else{
//key不存在
map.put(c,1);
}
}
// 5.遍历Map集合,输出结果
for(Character key : map.keySet()){
Integer value = map.get(key);
System.out.println(key +","+ value);
}
}
}
24.of方法
package ln.javatest.day12.demo02;
/*
JDK9的新特性:
List接口,Set接口,Map接口:里面增加了一个静态的方法of,可以给集合一次性添加多个元素
Static <E> List<E> of{ }
使用前提:
当集合中存储的元素的个数已经确定了,不在改变时使用
注意:
1.of方法只适用于List,Set,Map这三个接口
2.of方法的返回值是一个不能改变的集合,不能再使用add和put,会抛出异常
3.Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
*/
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Demo01JDK9 {
public static void main(String[] args) {
List<String> list = List.of("a", "b", "a");
//有重复,出错Set<String> set = Set.of("a", "b", "a");
Set<String> set = Set.of("a", "b", "c");
//key有重复,错误Map<String,Integer> map = Map.of("a",1, "b",,3, "a",2);
Map<String,Integer> map = Map.of("a",1, "b",3, "c",2);
//list集合中可以有重复的元素,Set和Map不行
System.out.println(list);
System.out.println(set);
System.out.println(map);
//错误list.add("d");
//错误set.add("d");
//错误map.add("d",6);
}
}
25.Debug调试程序
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug
使用方式:
在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里)
右键,选择Debug执行程序
程序就会停留在添加的第一个断点处
执行程序:
f8:逐行执行程序
f7:进入到方法中
shift+f8:跳出方法
f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
ctrl+f2:退出debug模式,停止程序
Console:切换到控制台
26.练习
package ln.javatest.day12.demo02;
/*
斗地主综合案例:有序版本
1.准备牌
2.洗牌
3.发牌
4.排序
5.看牌
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
public class DouDiZhu {
public static void main(String[] args) {
//1.准备牌
//创建一个Map集合,存储牌的索引和组装好的牌
HashMap<Integer,String> poker = new HashMap<>();
//创建一个List集合,存储牌的索引
ArrayList<Integer> pokerIndex = new ArrayList<>();
//定义两个集合,存储花色和牌的序号
List<String> colors = List.of("红桃","黑桃","梅花","方块");
List<String> numbers = List.of("2","A","K","Q","J","10","9","8","7","6","5","4","3");
//把大王和小王存储到集合中
//电话已一个牌的索引
int index = 0;
poker.put(index,"大王");
pokerIndex.add(index);
index++;
poker.put(index,"小王");
pokerIndex.add(index);
index++;
//循环嵌套遍历两个集合,组装52张牌,存储到集合中
for (String number : numbers) {
for (String color : colors) {
poker.put(index,color+number);
pokerIndex.add(index);
index++;
}
}
//2.洗牌
//使用Collections中的方法shuffle(List)
Collections.shuffle(pokerIndex);
//3.发牌
//定义4个集合,存储玩家牌的索引,和底牌的索引
ArrayList<Integer> play01 = new ArrayList<>();
ArrayList<Integer> play02 = new ArrayList<>();
ArrayList<Integer> play03 = new ArrayList<>();
ArrayList<Integer> diPai = new ArrayList<>();
//遍历存储牌索引的List集合,获取每一个牌的索引
for (int i = 0; i < pokerIndex.size(); i++) {
Integer in = pokerIndex.get(i);
//先判断底牌
if(i >= 51){
//给底牌发牌
diPai.add(in);
}else if(i % 3 == 0){
//给玩家1发牌
play01.add(in);
}else if(i % 3 == 1){
//给玩家2发牌
play02.add(in);
}else if(i % 3 == 2){
//给玩家3发牌
play03.add(in);
}
}
//4.排序
//使用Collections中的方法sort(List)
Collections.sort(play01);
Collections.sort(play02);
Collections.sort(play03);
Collections.sort(diPai);
//5.看牌
lookpoker("王嘉尔",poker,play01);
lookpoker("王嘉尔",poker,play02);
lookpoker("王嘉尔",poker,play03);
lookpoker("王嘉尔",poker,diPai);
}
/*
定义一个看牌的方法,提高代码的复用性
参数:
String name:玩家名称
HashMap<Integer,String> poker :存储牌的poker集合
ArrayList<Integer> list:存储玩家和底牌的List集合
查表法:
遍历玩家或者底牌集合,获取牌的索引
使用牌的索引,去Map集合中,找到对应的牌
*/
private static void lookpoker(String name,HashMap<Integer,String> poker,ArrayList<Integer> list) {
//输出玩家名称,不换行
System.out.print(name +":");
//遍历玩家或者底牌集合,获取牌的索引
for (Integer key : list) {
//使用牌的索引,去Map集合中,找到相应的牌
String value = poker.get(key);
System.out.print(value + " ");
}
//打印完每一个玩家的牌换行
System.out.println();
}
}