java.util.Collection接口
所有单列集合的最顶层的接口,里边定义了所有单列集合共性的方法
任意的单列集合都可以使用Collection接口中的方法
共性的方法:
public boolean add(E e):把给定的对象添加到当前集合中
public void clear():清空集合中所有的集合
public boolean remove(E e):把给定的对象在当前集合中删除
public boolean contains(E e):判断当前集合中是否包含给定的对象
public boolean isEmpty():判断当前集合是否为空
public int size():返回集合中元素的个数
public Object[] toArray():把集合中的元素,存储到数组中
java.util.Iterator接口:迭代器(对集合进行遍历)
有两个常用方法:
boolean hasNext():如果仍有元素可以迭代,则返回true
判断集合中还有没有下一个元素,有就返回true,没有就返回false
E next():返回迭代的下一个元素
取出集合中的下一个元素
Iterator迭代器,是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊
Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象
迭代器的使用步骤:
1、使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
3、使用Iterator接口中的方法next取出集合中的下一个元素
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Demo02Iterator { public static void main(String[] args) { //多态 Collection<String> coll = new ArrayList<>(); coll.add("小松狮"); coll.add("小锦鲤"); Iterator<String> it = coll.iterator(); /* boolean b = it.hasNext(); String s = it.next(); System.out.println(s); */ //发现使用迭代器取出集合中元素的代码,是一个重复的过程 // 所以我们可以使用循环优化 // 不知道集合中有多少元素,使用while循环 // 循环结束的条件,hasNext方法返回false while(it.hasNext()){ String e = it.next(); System.out.println(e); } } }
增强for循环:底层使用的也是迭代器,使用for循环的格式,简化了迭代器的书写
Collection extends Iterable:所有的单列集合都可以使用增强for
public interface Iterable实现这个接口允许对象成为“foreach”语句的目标
增强for循环:用来遍历集合和数组
格式:
for(集合/数组的数据类型 变量名 :集合名/数组名){
System.out.println(变量名);
}
public class Demo03Foreach { public static void main(String[] args) { demo01(); demo02(); } //使用增强for循环遍历集合 private static void demo02() { ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("小松狮"); arrayList.add("小锦鲤"); arrayList.add("小松狮1"); arrayList.add("小锦鲤1"); for (String b : arrayList) { System.out.println(b); } } //使用增强for循环遍历数组 private static void demo01() { int[] array = {1, 2, 3, 4, 5}; for (int a : array){ System.out.println(a); } } }
泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型
泛型也可以看做是一个变量,用来接收数据类型
E e:Element 元素
T t:Type 类型
ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型使用泛型
E:未知的数据类型
import java.util.ArrayList; import java.util.Iterator; public class Demo01Generic { public static void main(String[] args) { demo01(); demo02(); } /* 创建集合对象,使用泛型 好处: 1、避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型 2、把运行期异常提升到了编译期 弊端:泛型是什么类型,只能存储什么类型的数据 */ private static void demo02() { ArrayList<String> list = new ArrayList<>(); list.add("小松狮"); //list.add(111); list.add("小锦鲤"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String next = iterator.next(); System.out.println(next); } } /* * 创建集合对象,不使用泛型 * 好处:集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据 * 弊端:不安全,会引发异常 * */ private static void demo01() { ArrayList list = new ArrayList(); list.add("小松狮"); list.add(123); Iterator it1 = list.iterator(); while (it1.hasNext()){ Object next = it1.next(); System.out.println(next); //想要使用String类特有的方法,length获取字符串的长度;不能使用 //需向下转型 //会抛出ClassCastException //String s = (String) next; //System.out.println(s.length()); } } }
定义一个含有泛型的类,模拟ArrayList集合
泛型是一个未知的数据类型,当我们不确定什么数据类型的时候,可以使用泛型
泛型可以接受任意数据类型,可以使用Integer,String,Student…
创建对象的时候确定泛型的数据类型
public class Demo02Generic<E> { private E name; public E getName() { return name; } public void setName(E name) { this.name = name; } }
public class Demo03Generic { public static void main(String[] args) { Demo02Generic gc = new Demo02Generic(); gc.setName("字符串"); Object name = gc.getName(); System.out.println(name); Demo02Generic<Integer> gc2 = new Demo02Generic<>(); gc2.setName(222); Integer name1 = gc2.getName(); System.out.println(name1); Demo02Generic<String> gc3 = new Demo02Generic<>(); gc3.setName("小松狮"); String name2 = gc3.getName(); System.out.println(name2); } }
定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间
格式:
修饰符<泛型> 返回值类型 方法名(参数列表(使用泛型)){
方法体;
}
含有泛型的方法,在调用方法的时候确定泛型的数据类型
传递什么类型的参数,泛型就是什么类型
public class GenericMethod { //定义一个含有泛型的方法 public <M> void method01(M m){ System.out.println(m); } //定义一个含有泛型的静态方法 public static <S> void method02(S s){ System.out.println(s); } }
public class Demo04GenericMethod { public static void main(String[] args) { //创建一个GenericMethod对象 GenericMethod gm = new GenericMethod(); gm.method01(123); gm.method01("小松狮"); gm.method01(3.14); gm.method01(true); gm.method02("静态方法,不建议创建对象使用"); //静态方法通过类名.方法名(参数)可以直接使用 GenericMethod.method02("静态方法"); GenericMethod.method02(123); } }
/* 定义含有泛型的接口 */ public interface GenericInterface<I> { public abstract void method(I i); }
/* 含有泛型的接口,第一种使用方式: 定义接口的实现类,实现接口,指定接口的泛型 */ public class GenericInterfaceImpl1 implements GenericInterface<String>{ @Override public void method(String s) { System.out.println(s); } }
/* 含有泛型的接口,第二种使用方式: 接口使用什么泛型,实现类就使用什么泛型,类跟着接口走 就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型 */ public class GenericInterfaceImpl2<I> implements GenericInterface<I>{ @Override public void method(I i) { System.out.println(i); } }
/* 定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间 格式: 修饰符<泛型> 返回值类型 方法名(参数列表(使用泛型)){ 方法体; } 含有泛型的方法,在调用方法的时候确定泛型的数据类型 传递什么类型的参数,泛型就是什么类型 */ public class GenericMethod { //定义一个含有泛型的方法 public <M> void method01(M m){ System.out.println(m); } //定义一个含有泛型的静态方法 public static <S> void method02(S s){ System.out.println(s); } }
泛型的通配符:
?:代表任意的数据类型
使用方法:
不能创建对象使用
只能作为方法的参数使用
public class Demo06Generic { public static void main(String[] args) { ArrayList<Integer> list1 = new ArrayList<>(); list1.add(1); ArrayList<String> list2 = new ArrayList<>(); list2.add("小松狮"); printList(list1); printList(list2); // ArrayList<?> list3 = new ArrayList<?>();错误写法! } /* 定义一个方法,能遍历所有类型的ArrayList集合 这时候我们不知道ArrayList集合使用什么数据类型,可以使用泛型的通配符?来接受数据类型 注意:泛型没有继承概念的 */ public static void printList(ArrayList<?> list){ Iterator<?> it = list.iterator(); while (it.hasNext()){ //取出的元素是Object,可以接收任意的数据类型 Object next = it.next(); System.out.println(next); } } }
泛型的上限限定:?extends E 代表使用的泛型只能是E类型的子类/本身
泛型的下限限定:?super E 代表使用的泛型只能是E类型的父类/本身
import java.util.ArrayList; import java.util.Collections; /* 斗地主案例: 1、准备牌 2、洗牌 3、发牌 4、看牌 */ public class DouDiZhu { public static void main(String[] args) { //1、准备牌 //定义一个存储54张牌的ArrayList集合,泛型使用String ArrayList<String> poker = new ArrayList<>(); //定义两个数组,一个数组存储牌的花色,一个数组存储牌的序号 String[] colors = {"♠", "♥", "♣", "♦"}; String[] numbers = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"}; //先把大王和小王存储到poker集合中 poker.add("大王"); poker.add("小王"); //循环嵌套遍历两个数组,组装52张牌 for (String number : numbers){ for (String color : colors){ //System.out.println(color + number); //把组装好的牌存储到poker集合中 poker.add(color + number); } } //2、洗牌 //使用集合的工具类Collections中的方法 //static void shuffle(List<?> List) Collections.shuffle(poker); //System.out.println(poker); //3、发牌 //定义4个集合,存储玩家的牌和底牌 ArrayList<String> player01 = new ArrayList<>(); ArrayList<String> player02 = new ArrayList<>(); ArrayList<String> player03 = new ArrayList<>(); ArrayList<String> diPai = new ArrayList<>(); /* 遍历poker集合,获取每一张牌 使用poker集合的索引%3给3个玩家轮流发牌 剩余3张牌给底牌 注意:先判断底牌(i>=51),否则牌就发完了 */ for (int i = 0; i < poker.size(); i++){ //获取每一张牌 String p = poker.get(i); //轮流发牌 if (i >= 51){ diPai.add(p); }else if (i % 3 == 0){ player01.add(p); }else if (i % 3 == 1){ player02.add(p); }else if (i % 3 == 2){ player03.add(p); } } //4、看牌 System.out.println("赌神:" + player01); System.out.println("赌侠:" + player02); System.out.println("赌圣:" + player03); System.out.println("底牌:" + diPai); } }
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:索引越界异常
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Demo01List { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("小松狮"); list.add("小锦鲤"); list.add("小松狮1"); list.add("小锦鲤1"); System.out.println(list); list.add(2,"哈喽"); System.out.println(list); String remove = list.remove(3); System.out.println(remove); System.out.println(list); String set = list.set(2, "小松狮1"); System.out.println(set); System.out.println(list); //List集合的三种遍历 //普通for循环 for (int i = 0; i < list.size(); i++){ String s = list.get(i); System.out.println(s); } //使用迭代器 Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String next = iterator.next(); System.out.println(next); } //使用增强for循环 for (String s: list) { System.out.println(s); } } }
java.util.LinkedList集合 implements List接口
LinkedList集合的特点:
1、底层是一个链表结构:查询慢,增删快
2、里边包含了大量操作首尾元素的方法
注意:使用LinkedList集合特有的方法,不能使用多态
public void addFirst(E e):将指定元素插入此列表的开头
public void addLast(E e):将指定元素添加到此列表的结尾
public E getFirst():返回此列表的第一个元素
public E getLast():返回此列表的最后一个元素
public E removeFirst():移除并返回此列表的第一个元素
public E removeLast():移除并返回此列表的最后一个元素
public E pop():从此列表所表示的堆栈处弹出一个元素
public void push(E e):将元素推入此列表所表示的堆栈
public boolean isEmpty():如果列表不包含元素,则返回true
public class Demo02LinkedList { public static void main(String[] args) { demo01(); demo02(); demo03(); } private static void demo03() { LinkedList<String> linked = new LinkedList(); linked.add("小松狮"); linked.add("小锦鲤"); linked.add("小松狮1"); linked.add("小锦鲤1"); System.out.println(linked); String s = linked.removeFirst();//等效于pop(); System.out.println(s); String s1 = linked.removeLast(); System.out.println(s1); } private static void demo02() { LinkedList<String> linked = new LinkedList(); linked.add("小松狮"); linked.add("小锦鲤"); linked.add("小松狮1"); linked.add("小锦鲤1"); System.out.println(linked); if (!linked.isEmpty()) { String first = linked.getFirst(); System.out.println(first); String last = linked.getLast(); System.out.println(last); } } private static void demo01() { LinkedList<String> linked = new LinkedList(); linked.add("小松狮"); linked.add("小锦鲤"); linked.add("小松狮1"); linked.add("小锦鲤1"); System.out.println(linked); linked.addFirst("111");//等效于push(); linked.addLast("333"); System.out.println(linked); } }
java.util.Set接口 extends Collection接口
Set接口的特点:
1、不允许存储重复的元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历
java.util.HashSet集合 implements Set接口
HashSet特点:
1、不允许存储重复的元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历
3、是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4、底层是一个哈希表结构(查询的速度非常快)
public class Demo01Set { public static void main(String[] args) { Set<Integer> set = new HashSet<>(); set.add(1); set.add(2); set.add(3); set.add(1); Iterator<Integer> iterator = set.iterator(); while (iterator.hasNext()){ Integer next = iterator.next(); System.out.println(next); } for (Integer i : set){ System.out.println(i); } } }
哈希值:是一个十进制的整数,由系统随机给出
(就是对象的地址值,是一个逻辑地址,模拟出来的地址,不是数据实际存储的物理地址)
在Object类有一个方法,可以获取对象的哈希值
int hashCode()返回该对象的哈希码值
public class Demo02HashCode { public static void main(String[] args) { Person one = new Person(); int i = one.hashCode(); System.out.println(i);//2003749087 Person two = new Person(); int i1 = two.hashCode(); System.out.println(i1);//1324119927 System.out.println(one);//Day13.Demo04.Person@776ec8df System.out.println(two);//Day13.Demo04.Person@4eec7777 System.out.println(one == two);//false } }
Set集合不允许存储重复元素的原理
Set集合在调用add方法的时候,add方法会调用元素的hashCode方法和equals发给发,判断元素是否重复
前提:存储的元素必须重写hashCode方法和equals方法
import java.util.Objects; public class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } @Override public String toString() { return "Person{" + "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; } }
import java.util.HashSet; /* HashSet存储自定义类型元素 要求: 同名同年龄的人,视为同一个人,只能存储一次 */ public class Demo04HashSetSavePerson { public static void main(String[] args) { HashSet<Person> set = new HashSet<>(); Person one = new Person("小松狮",18); Person two = new Person("小锦鲤",18); Person three = new Person("小松狮",18); set.add(one); set.add(two); set.add(three); System.out.println(set); } }
java.util.LinkedHashSet集合 extends HashSet集合
LinkedHashSet集合特点:
底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序
public class Demo05LinkedHashSet { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("abc"); set.add("123"); set.add("123"); set.add("小松狮"); System.out.println(set);//[123, abc, 小松狮] 无序,不允许重复 LinkedHashSet<String> linked = new LinkedHashSet<>(); linked.add("123"); linked.add("abc"); linked.add("abc"); linked.add("小锦鲤"); System.out.println(linked);//[123, abc, 小锦鲤] 有序,不允许重复 } }
可变参数
使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
使用格式:定义方法时使用
修饰符 返回值类型 方法名(数据类型…变量名){}
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
传递的参数个数,可以是0个(不传递),1,2,…多个
注意事项:
1、一个方法的参数列表,只能有一个可变参数
2、如果方法的参数有多个,那么可变参数必须卸载参数列表的末尾
public class Demo06VarArgs { public static void main(String[] args) { int num = add(1); int num2 = add(1, 2, 3); System.out.println(num2); } /* 定义计算(0-n)个整数和的方法 已知:计算整数的和,数据类型已经确定int 但是参数的个数不确定,不知道要计算几个整数的和,就可以使用可变参数 */ public static int add(int ... arr){ int sum = 0; for (int i: arr) { sum += i; } return sum; } //public static int method(int ...a, String ... b){ //}错误! //public static int method(String b, double c, int ... a){ //?正确 }
java.util.Collections是集合工具类,用来对集合进行操作,部分方法如下:
public static boolean addAll(Collections c, T… elements):往集合中添加一些元素
public static void shuffle(List<?> list)打乱集合顺序
public class Demo01Collections { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); Collections.addAll(list,"a", "b", "c", "d"); System.out.println(list);//[a, b, c, d] Collections.shuffle(list); System.out.println(list);//[d, b, a, c] } }
public static void sort(List<?> list):将集合中元素按照默认规则排序
sort使用前提:被排序的集合里边存储的元素,必须实现Comparable,重写接口中的方法compareTo定义排序的规则
Comparable接口的排序规则:
自己(this)-参数:升序
public class Person implements Comparable<Person>{ private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "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; } @Override public int compareTo(Person o) { //return 0;认为元素都是相同的 return this.getAge() - o.getAge();//升序 //return o.getAge() - this.getAge();//降序 } }
public class Demo01Collections { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); Collections.addAll(list,"a", "b", "c", "d"); Collections.shuffle(list); System.out.println("========="); ArrayList<Integer> list1 = new ArrayList<>(); list1.add(1); list1.add(6); list1.add(3); Collections.sort(list1); System.out.println(list1);//[1, 3, 6]默认升序 ArrayList<String> list2 = new ArrayList<>(); list2.add("a"); list2.add("A"); list2.add("t"); Collections.sort(list2); System.out.println(list2);//[A, a, t] ArrayList<Person> list3 = new ArrayList<>(); list3.add(new Person("小松狮",18)); list3.add(new Person("小松狮",16)); list3.add(new Person("小松狮",20)); Collections.sort(list3); System.out.println(list3); } }
将集合中元素按照指定规则排序
public static void sort(List list, Comparator<? super T>)
Comparator和Comparable区别:
Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较的规则compareTo方法
Comparator:相当于找一个第三方来比较
Comparator的排序规则:
o1-o2:升序;o2-o1:降序
public class Demo02Sort { public static void main(String[] args) { ArrayList<Integer> list1 = new ArrayList<>(); list1.add(1); list1.add(6); list1.add(3); Collections.sort(list1, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1;//降序 } }); System.out.println(list1);//[6, 3, 1] ArrayList<Student> list2 = new ArrayList<>(); list2.add(new Student("小松狮",18)); list2.add(new Student("小松狮",16)); list2.add(new Student("小松狮",20)); Collections.sort(list2, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); } }); System.out.println(list2); } }
java.util.Map<k,v>集合
Map集合的特点:
1、Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
2、Map集合中的元素,key和value的数据类型可以相同,也可以不同
3、Map集合中的元素,key是不允许重复的,value是可以重复的
4、Map集合中的元素,key和value是一一对应
java.util.HashMap<k,v>集合 implements Map<k,v>接口
HashMap集合的特点:
1、HashMap集合底层是哈希表:查询速度特别快
2、HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致
java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
LinkedHashMap的特点:
1、LinkedHashMap集合底层是哈希表+链表(保证迭代的顺序)
2、LinkedHashMap集合是一个有序的集合,存储元素和取出元素顺序是一致的
Map集合的方法:
public V put(K key, V value):把指定的键与指定的值添加到Map集合中
返回值:V
存储键值对的时候,key不重复,返回值V是null
存储键值对的时候,ke重复,会使用新的value替换map中重复的value,返回被替换的value值
public V remove(Object key):把指定的键所对应的键值对元素再Map集合中删除,返回被删除元素的值
返回值:V
key存在,V返回被删除的值
key不存在,V返回null
public V get(Object key)根据指定的键,在Map集中中获取对应的值
返回值:V
key存在,v返回被删除的值
key不存在,V返回null
boolean containsKey(Object key)判断集合中是否包含指定的键
包含返回true,不包含返回false
public class DemoMap { public static void main(String[] args) { demo01(); demo02(); demo03(); demo04(); } private static void demo04() { Map<String, Integer> map = new HashMap<>(); map.put("小松狮",17); map.put("小锦鲤",18); map.put("小松狮1",17); boolean b1 = map.containsKey("小锦鲤"); System.out.println(b1);//true boolean b2 = map.containsKey("小锦鲤3"); System.out.println(b2);//false } private static void demo03() { Map<String, Integer> map = new HashMap<>(); map.put("小松狮",17); map.put("小锦鲤",18); map.put("小松狮1",17); Integer v1 = map.get("小锦鲤"); System.out.println(v1);//18 Integer v2 = map.get("小松狮4"); System.out.println(v2);//null } private static void demo02() { Map<String, Integer> map = new HashMap<>(); map.put("小松狮",17); map.put("小锦鲤",18); map.put("小松狮1",17); System.out.println(map);//{小锦鲤=18, 小松狮=17, 小松狮1=17} Integer v1 = map.remove("小松狮"); System.out.println(v1);//17 Integer v2 = map.remove("小松狮3"); System.out.println(v2);//null System.out.println(map);//{小锦鲤=18, 小松狮1=17} } private static void demo01() { Map<String, String> map = new HashMap<>(); String v1 = map.put("小松狮", "小锦鲤"); System.out.println(v1);//null String v2 = map.put("小松狮", "小锦鲤1"); System.out.println(v2);//小锦鲤 System.out.println(map);//{小松狮=小锦鲤1} } }
Map集合的第一种遍历方式:通过键找值的方式
Map集合中的方法:Set keySet()
实现步骤:
1、使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
2、遍历set集合,获取Map集合中的每一个key
3、通过Map集合中的方法get(key),通过key找到value
public class Demo01KeySet { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("小松狮",17); map.put("小锦鲤",18); map.put("小松狮1",17); Set<String> set = map.keySet(); Iterator<String> iterator = set.iterator(); while (iterator.hasNext()){ String key = iterator.next(); Integer value = map.get(key); System.out.println(key + "-" + value); } System.out.println("========="); for(String key : map.keySet()){ Integer value = map.get(key); System.out.println(key + "-" + value); } } }
Map集合遍历的第二种方式:使用Entry对象遍历
Map.Entry<K,V>:在Map接口中有一个内部接口Entry
作用:当Map集合一创建,那么就会在Map集合中创建一个Entry对象,用来记录键与值
(键值对对象,键与值的映射关系)
Map集合中的方法:Set<Map.Entry<K,V>> entrySet()
实现步骤:
1、使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
2、遍历Set集合,获取每一个Entry对象
3、使用Entry对象中的方法getKey()和getValue()获取键与值
public class Demo02EntrySet { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("小松狮",17); map.put("小锦鲤",18); map.put("小松狮1",17); Set<Map.Entry<String, Integer>> set = map.entrySet(); Iterator<Map.Entry<String, Integer>> it = set.iterator(); while (it.hasNext()){ Map.Entry<String, Integer> entry = it.next(); String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + "-" + value); } for(Map.Entry<String, Integer> entry: set){ String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + "-" + value); } } }
HashMap存储自定义类型键值
Map集合保证key是唯一的:
作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
public class Demo03HashMapSavePerson { public static void main(String[] args) { demo01(); demo02(); } /* HashMap存储自定义类型键值 key:Person类型 Person类就必须重写hashCode方法和equals方法,以保证key唯一 value:String类型 value可以重复 */ private static void demo02() { HashMap<Person, String> map = new HashMap<>(); map.put(new Person("小松狮",18), "哈哈"); map.put(new Person("小锦鲤",17), "嘿嘿"); map.put(new Person("小松狮1",18), "嘎嘎"); map.put(new Person("小松狮",18), "咕咕"); Set<Map.Entry<Person, String>> set = map.entrySet(); for (Map.Entry<Person, String> entry : set){ Person 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 demo01() { HashMap<String, Person> map = new HashMap<>(); map.put("哈哈",new Person("小松狮",17)); map.put("嘿嘿",new Person("小锦鲤",18)); map.put("嘎嘎",new Person("小松狮1",19)); map.put("哈哈",new Person("小松狮2",17)); Set<String> set = map.keySet(); for (String key : set){ Person value = map.get(key); System.out.println(key + "-" + value); } } }
java.util.LinkedHashMap<K,V> extends HashMap<k,v>
Map接口的哈希表和链接列表实现,具有可预知的迭代顺序
底层原理:
哈希表+链表(记录元素的顺序)
public class Demo04LinkedHashMap { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.put("a","a"); map.put("c","c"); map.put("b","b"); map.put("a","d"); System.out.println(map);//key不允许重复,无序集合 LinkedHashMap<String, String> linked = new LinkedHashMap<>(); linked.put("a","a"); linked.put("c","c"); linked.put("b","b"); linked.put("d","d"); System.out.println(linked);//key不允许重复,有序集合 } }
java.util.Hashtable<K,V>集合 implements Map<K,V>接口
Hashtable:底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
HashMap集合(之前学的所有集合):可以存储null值,null键
Hashtable集合,不能存储null值,null键
Hashtable和Vector集合一样,在jdk1.2版本之后被取代了
Hashtable的子类Properties依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合
public class Demo01HashTable { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.put(null, "a"); map.put("b", null); map.put(null, null); System.out.println(map);//{null=null, b=null} Hashtable<String, String> table = new Hashtable<>(); //table.put(null, "a");//.NullPointerException //table.put("b", null);//.NullPointerException //table.put(null, null);//.NullPointerException } }
计算一个字符串中每个字符出现的次数
import java.util.HashMap; import java.util.Scanner; /* 练习:计算一个字符串中每个字符出现次数 分析: 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集合,输出结果 */ public class Demo02MapTest { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入一个字符串:"); String str = scanner.next(); HashMap<Character, Integer> map = new HashMap<>(); for (char c: str.toCharArray()){ if (map.containsKey(c)){ Integer value = map.get(c); value++; map.put(c, value); }else { map.put(c,1); } } for (Character key: map.keySet()){ Integer value = map.get(key); System.out.println(key + "-" + value); } } }
JDK9的新特性:
List接口,Set接口,Map接口:里边增加了一个静态方法of,可以给集合一次性添加多个元素
static List of(E… elements)
使用前提:
当集合中存储的元素的个数已经确定,不再改变时使用
注意:
1、of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
2、of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
3、Set接口和Map接口再调用of方法时,不能有重复元素,否则会抛出异常
public class Demo03 { public static void main(String[] args) { List<String> list = List.of("a", "b", "c", "a"); System.out.println(list);//[a, b, c, a] //list.add("s");//错误!UnsupportedOperationException //Set<String> set = Set.of("a", "b", "a", "c", "d"); //System.out.println(set);//错误!IllegalArgumentException,有重复元素 Set<String> set = Set.of("a", "b", "c", "d"); System.out.println(set);//[d, c, b, a] Map<String, String> map = Map.of("小松狮", "17", "小锦鲤", "18"); System.out.println(map);//{小松狮=17, 小锦鲤=18} } }
Debug调试程序:
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug
使用方式:
在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到那里)
右键,选择Debug执行程序
程序就会停留在添加的第一个断点处
执行程序:
F8:逐行执行程序
F7:进入到方法中
shift+F8:跳出方法
F9:跳到下一个断电,如果没有下一个断电,那么就结束程序
ctrl+F2:退出Debug模式,停止程序
Console:切换到控制台
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++; } } //System.out.println(poker); //System.out.println(pokerIndex); //2、洗牌 Collections.shuffle(pokerIndex); //3、发牌 //定义四个集合,存储玩家牌的索引和底牌的索引 ArrayList<Integer> playerA = new ArrayList<>(); ArrayList<Integer> playerB = new ArrayList<>(); ArrayList<Integer> playerC = 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){ playerA.add(in); }else if (i % 3 == 1){ playerB.add(in); } else if (i % 3 == 2){ playerC.add(in); } } //4、排序 Collections.sort(playerA); Collections.sort(playerB); Collections.sort(playerC); Collections.sort(diPai); /* 5、看牌 定义一个看牌的方法,提高代码的复用性 参数: String name:玩家名称 HashMap<Integer, String> poker:存储牌的poker集合 ArrayList<Integer> list:存储玩家和底牌的List集合 查表法: 遍历玩家或者底牌集合,获取牌的索引 使用牌的索引,去Map集合中,找到对应的牌 */ lookPoker("赌神", poker, playerA); lookPoker("赌侠", poker, playerB); lookPoker("赌圣", poker, playerC); lookPoker("底牌", poker, diPai); } public static void lookPoker(String name, HashMap<Integer, String> poker, ArrayList<Integer> list){ //输出玩家名称,不换行 System.out.print(name + ":"); //遍历玩家或底牌集合,获取牌的索引 for (Integer key : list){ String value = poker.get(key); System.out.print(value + " "); } System.out.println(); } }