一、集合框架
1.1 概述
集合:集合是Java中提供的一种容器,可以用来存储多个数据。
集合和数组:
- 数组的长度是固定的。集合的长度是可变的。
int[] arr = new int[10];
- 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一样,在开发中一般当对象多的时候,使用集合进行存储。
1.2 集合框架
学习顶层:学习顶层接口/抽象类中共性的方法,所有的子类都可以使用。
使用底层:上层不是接口就是抽象类,无法创建对象使用,需要使用底层的子类创建对象使用
二、Collection接口
java.util.Collection
- boolean add(E e) 确保此集合包含指定的元素(可选操作)。
- void clear() 从此集合中删除所有元素(可选操作)。
- boolean contains(Object o) 如果此集合包含指定的元素,则返回 true 。
- boolean isEmpty() 如果此集合不包含元素,则返回 true 。
- boolean remove(Object o) 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
- int size() 返回此集合中的元素数。
- Object[] toArray() 返回一个包含此集合中所有元素的数组。
三、Iterator迭代器接口
java.util.Iterator 接口:迭代器(对集合进行遍历)。
3.1 常用方法
boolean hasNext() //如果仍有元素可以迭代,则返回true。判断集合中还有没有下一个元素,有就返回true,没有则返回false
E next() //返回迭代的下一个元素
Collection接口中有一个方法iterator(),这个方法返回的就是迭代器的实现类对象
Iterator<E> iterator() 返回在次Collection的元素上进行迭代的迭代器
使用步骤:
① 使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)。
② 使用Iterator接口中的方法hasNext判断还有没有下一个元素。
③ 使用Iterator接口中的方法next取出集合中的下一个元素
注意:Iterator接口是有泛型的迭代器的泛型跟着集合走。集合什么泛型,他就什么泛型
实现原理:
3.2 增强for循环
底层使用的也是迭代器,只是使用for循环的格式,简化了迭代器的书写(JDK1.5以后的新特性)。
for(集合/数组的数据类型 变量名:集合名/数组名){
//...
}
四、泛型
4.1 概念
泛型是一种未知的数据类型,但我们不知道使用什么数据类型的时候,就用泛型。
也可以看成一种变量,用来接收数据类型。
创建集合对象,不使用泛型时:
好处:集合不适用泛型,默认的类型就是Object类型,可以存储任意类型的数据
弊端:不安全,会引发异常。
创建集合对象,使用泛型:
- 好处:避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型;把运行期异常(代码运行之后抛出的异常),提升到了编译期(写代码的时候报错)。
- 弊端:泛型是什么类型,只能存储什么类型。
4.2 含有泛型的类
在定义类时在类名后面加个,创建对象时声明E是什么类型即可。
public class GenericClass<E> {
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
public class Demo02GenericClass {
public static void main(String[] args) {
//不写泛型默认为Object类型
GenericClass gc = new GenericClass();
gc.setName("test");
Object obj = gc.getName();
//创建GenericClass对象,泛型使用Integer类型
GenericClass<Integer> gc2 = new GenericClass<>();
gc2.setName(1);
Integer name = gc2.getName();
System.out.println(name);
//创建GenericClass对象,泛型使用String类型
GenericClass<String> gc3 = new GenericClass<>();
gc3.setName("小明");
String name1 = gc3.getName();
System.out.println(name1);
}
}
4.3 含有泛型的方法
泛型定义在方法的 修饰符 和 返回值 类型之间
修饰符<泛型> 返回值类型 方法名(参数列表(使用泛型)){
//方法体
}
在调用时,要确认数据类型。
public class GenericMethod {
//定义一个含有泛型的方法
public <M> void method01(M m){
System.out.println(m);
}
}
public class Demo03GenericMethod {
public static void main(String[] args) {
//创建GenericMethod对象
GenericMethod gm = new GenericMethod();
/*
调用含有泛型的方法method01
传递什么类型,泛型就是什么类型
*/
gm.method01(10);
gm.method01("abc");
gm.method01(8.8);
gm.method01(true);
}
}
4.4 含有泛型的接口
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);
}
}
第二种使用方式 :接口使用什么泛型,实现类就使用什么泛型,类跟着接口走,就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。
// 这里的泛型必须保持一致为同一个名称(如:同为I),否则会报错
public class GenericInterfaceImpl2<I> implements GenericInterface<I> {
@Override
public void method(I i) {
System.out.println(i);
}
}
public class Demo04GenericInterface {
public static void main(String[] args) {
//创建GenericInterfaceImpl1对象
GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
gi1.method("字符串");
//创建GenericInterfaceImpl2对象
GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
gi2.method(10);
GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();
gi3.method(8.8);
}
}
4.5 泛型通配符
① 概念
不能创建对象使用,只能作为方法的参数使用。
public class Demo05Generic {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(2);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArray(list01);
printArray(list02);
//ArrayList<?> list03 = new ArrayList<?>();//报错
}
/*
定义一个方法,能遍历所有类型的ArrayList集合
这时候我们不知道ArrayList集合使用什么数据类型,可以泛型的通配符?来接收数据类型
注意:
泛型是没有继承概念的,所以?不能用Object来代替
*/
public static void printArray(ArrayList<?> list){
//使用迭代器遍历集合
Iterator<?> it = list.iterator();
while(it.hasNext()){
//it.next()方法,取出的元素是Object,可以接收任意的数据类型
Object o = it.next();
System.out.println(o);
}
}
}
② 受限泛型
- 泛型的上限限定:
? extends E
代表使用的泛型只能是E类型的子类/本身 - 泛型的下限限定:
? super E
代表使用的泛型只能是E类型的父类/本身
public class Demo06Generic {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement1(list1);
//getElement1(list2);//报错
getElement1(list3);
//getElement1(list4);//报错
//getElement2(list1);//报错
//getElement2(list2);//报错
getElement2(list3);
getElement2(list4);
/*
类与类之间的继承关系
Integer extends Number extends Object
String extends Object
*/
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
}
五、List接口
java.util.List 有序、有索引、允许存储相同的元素
5.1 常用方法
public void add(int index,E element) 将指定的元素添加到该集合中的指定位置上
public E get(int index) 返回集合中指定位置的元素
public E remove(int index) 移除列表中指定位置的元素,返回的是被移除的元素
public E set(int index,E element) 用指定元素替换集合中指定位置的元素,返回更新前的元素
5.2 LinkedList
java.util.LinkedList
- ArrayList集合:底层是 数组结构 ,多线程,查询快,增删慢。
- LinkedList集合:① 底层是一个 链表结构 ,多线程,查询慢,增删快;② 里面包含了大量操作首尾元素的方法。
注意:使用LinkedList集合特有的方法,不能使用多态。
① 添加相关的方法
public void addFirst(E e) 将指定元素添加到此列表的开头,此方法等效于public void push(E e)方法
public void addLast(E e) 将指定元素添加到此列表的结尾,此方法等效于add()
② 获取相关的方法
public E getFirst() 返回列表的第一个元素
public E getLast() 返回列表的最后一个元素
注意:如果集合中无元素,会报错。
③ 移除相关的方法
public E removeFirst() 移除并返回此列表的第一个元素,等效于public E pop()
public E removeLast() 移除并返回此列表的最后一个元素
5.3 Vector
底层是 数组结构 ,单线程,速度慢,后来被ArrayList取代。
六 、Set接口
java.util.Set
6.1 特点
① 不允许存储重复的元素。
② 没有索引,没有带索引的方法,也不能使用普通的for循环。
6.2 hashSet
6.2.1 特点
① 不允许存储重复的元素。
② 没有索引,没有带索引的方法,也不能使用普通的for循环。
③ 无序集合,存储元素和取出元素的顺序有可能不一致。
④ 底层是一个哈希表结构(查询的速度非常快)。
6.2.2 哈希值
哈希值是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来的地址,不是数据实际存储的物理地址)。
在Object类中有一个方法,可以获取对象的hash值
int hashCode()
返回该对象的哈希码值
对象的地址值就是用的hashCode()方法返回的哈希码的十六进制,但是字符串String类重写了hashCode方法。
6.2.3 哈希表
在jdk1.8版本之前,哈希表 = 数组 + 链表
在jdk1.8版本之后:
哈希表 = 数组 +链表
哈希表 = 数组 + 红黑树(提高查询的速度)
Set集合不允许存储重复元素的原理:
6.2.4 存储引用类型
要求:同名和同年龄的人,视为同一个人,只能在Hashset集合中存储一次。
则必须重写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;
}
}
public class Demo03HashSetSavePerson {
public static void main(String[] args) {
//创建HashSet集合存储Person
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("小美女",18);
Person p2 = new Person("小美女",18);
Person p3 = new Person("小美女",19);
System.out.println(p1.hashCode());//1967205423
System.out.println(p2.hashCode());//42121758
System.out.println(p1==p2);//false
System.out.println(p1.equals(p2));//true,若不重写,Object类中的equals方法和“==”是一样的,比较的都是内存地址值
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
}
}
6.3 LinkedHashSet
java.util.LinkedHashSet 集合继承了HashSet集合
① 底层是一个哈希表(数组+链表/红黑树)+ 链表,比HashSet多了一条链表(记录元素的存储顺序),保证元素有序。
② 有序,不允许重复
七、可变参数
JDK1.5之后的新特性
7.1 使用格式
- 当方法的参数列表数据类型已经确定,但是参数个数不确定,就可以使用可变参数。
修饰符 返回值类型 方法名(数据类型...变量名){}
7.2 原理
可变参数的底层就是一个数组,根据传递参数个数的不同,会创建不同长度的数组,来存储这些参数,传递的参数个数,可以是0个(不传递),1个,2个…多个。
这样这个参数列表中的变量名就就变成了相应类型的数组。
public static int add(int...arr){
//定义一个初始化的变量,记录累加求和
int sum = 0;
//遍历数组,获取数组中的每一个元素
for (int i : arr) {
//累加求和
sum += i;
}
//把求和结果返回
return sum;
}
7.3 注意
① 一个方法的参数列表只能有一个可变参数
② 如果一个方法的参数有多个,那么可变参数必须写在参数列表的末尾。
7.4 特殊写法
public static void method(Object...obj){}//这里可以接收任意数据类型的参数
八、Collections工具类
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) //将集合中的元素按照默认规则进行排序
这里的 T 类型的数据,必须实现Comparable接口,并在类中重写接口中的方法compareTo定义。
Comparable接口的排序规则:
- 自己(this) - 参数 //这是升序
- 参数 - 自己(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;//认为元素都是相同的
//自定义比较的规则,比较两个人的年龄(this,参数Person)
//return this.getAge() - o.getAge();//年龄升序排序
return o.getAge() - this.getAge();//年龄降序排序
}
}
public class Demo02Sort {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(3);
list01.add(2);
System.out.println(list01);//[1, 3, 2]
//public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
Collections.sort(list01);//默认是升序
System.out.println(list01);//[1, 2, 3]
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("c");
list02.add("b");
System.out.println(list02);//[a, c, b]
Collections.sort(list02);
System.out.println(list02);//[a, b, c]
ArrayList<Person> list03 = new ArrayList<>();
list03.add(new Person("张三",18));
list03.add(new Person("李四",20));
list03.add(new Person("王五",15));
System.out.println(list03);//[Person{name='张三', age=18}, Person{name='李四', age=20}, Person{name='王五', age=15}]
Collections.sort(list03);
System.out.println(list03);
}
}
public static <T> void sort(List<T> list,Comparator<? super T>) //将集合中元素按照指定规则排序
Comparator 与 Comparable的区别
① Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较规则comparaTo方法
② Comparator:相当于找一个第三方的裁判,来进行比较(需要重写compare方法)
Comparator排序规则:
- 第一个参数 - 第二个参数 //升序
- 第二个参数 - 第一个参数 //降序
public class Demo03Sort {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(3);
list01.add(2);
System.out.println(list01);//[1, 3, 2]
Collections.sort(list01, new Comparator<Integer>() {
//重写比较的规则
@Override
public int compare(Integer o1, Integer o2) {
//return o1-o2;//升序
return o2-o1;//降序
}
});
System.out.println(list01);
ArrayList<Student> list02 = new ArrayList<>();
list02.add(new Student("a迪丽热巴",18));
list02.add(new Student("古力娜扎",20));
list02.add(new Student("杨幂",17));
list02.add(new Student("b杨幂",18));
System.out.println(list02);
/*Collections.sort(list02, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序排序
return o1.getAge()-o2.getAge();
}
});*/
//扩展:了解
Collections.sort(list02, 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(list02);
}
}
九、Map接口
java.util.Map public interface Map<K,V>
9.1 特点
① Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)。
② Map集合中的元素,key和value的数据类型可以相同也可以不同。
③ Map集合中的元素,key是不允许重复的,value是可以重复的。
④ Map集合中的元素,key和value是一一对应的。
9.1.1 HashMap
java.util.HashMap
① HashMap底层是哈希表,查询的速度特别快。
JDK1.8之前:数组 + 单向链表。
JDK1.8之后:数组 + 单向链表/红黑树(链表的长度超过8):提高查询速度
② HashMap是一个无序集合,存储元素和取出元素的顺序有可能不一致。
9.1.2 LinkedHashMap
java.util.LinkedHashMap
① LinkedHashMap集合底层是哈希表+链表(保证迭代顺序)
② LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的。
9.2 Map常用方法
① put方法
public V put(K key , V value) //把指定的键值对添加到Map集合中
如果key已存在,返回null;如果不存在,则用新的value替换旧的value,返回旧的value值。
② remove方法
public V remove (Object key) //把指定的键值对元素,在Map中删除,返回被删除的元素的值
如果key存在,则返回被删除的值;如果key不存在,则返回null。
③ get方法
public V get(Object key) //根据指定的键,在Map集合中获取对应的值
如果key存在,返回对应的value值;如果key不存在,则返回null。
④ containsKey方法
boolean containsKey(Object key) //是否存在指定key
如果key存在,返回true;如果key不存在,则返回false。
⑤ keySet方法
Set<K> keySet() //返回次映射中包含的键的Set集合
9.3 Map的遍历
9.3.1 keySet()
Map集合的第一种遍历方式,通过键找值的方式:
public class Demo02KeySet {
public static void main(String[] args) {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖",165);
map.put("林志玲",178);
//1.使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
Set<String> set = map.keySet();
//2.遍历set集合,获取Map集合中的每一个key
//使用迭代器遍历Set集合
Iterator<String> it = set.iterator();
while (it.hasNext()){
String key = it.next();
//3.通过Map集合中的方法get(key),通过key找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
System.out.println("-------------------");
//使用增强for遍历Set集合
for(String key : set){
//3.通过Map集合中的方法get(key),通过key找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
System.out.println("-------------------");
//使用增强for遍历Set集合
for(String key : map.keySet()){
//3.通过Map集合中的方法get(key),通过key找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
}
}
9.3.2 entrySet()
Entry是Map的内部类
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的Set集合
Map集合的第二种遍历方式,通过Entry对象遍历:
public class Demo03EntrySet {
public static void main(String[] args) {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖",165);
map.put("林志玲",178);
//1.使用Map集合中 的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
Set<Map.Entry<String, Integer>> set = map.entrySet();
//2.遍历Set集合,获取每一个Entry对象
//使用迭代器遍历Set集合
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);
}
System.out.println("-----------------------");
for(Map.Entry<String,Integer> entry:set){
//3.使用Entry对象中的方法getKey()和getValue()获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
}
}
9.4 存储引用类型
Map集合保证key是唯一的:
作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一。
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 String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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);
}
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 class Demo01HashMapSavePerson {
public static void main(String[] args) {
show02();
}
private static void show02() {
//创建HashMap集合
HashMap<Person,String> map = new HashMap<>();
//往集合中添加元素
map.put(new Person("女王",18),"英国");
map.put(new Person("秦始皇",18),"秦国");
map.put(new Person("普京",30),"俄罗斯");
map.put(new Person("女王",18),"毛里求斯");
//使用entrySet和增强for遍历Map集合
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);
}
}
private static void show01() {
//创建HashMap集合
HashMap<String,Person> map = new HashMap<>();
//往集合中添加元素
map.put("北京",new Person("张三",18));
map.put("上海",new Person("李四",19));
map.put("广州",new Person("王五",20));
map.put("北京",new Person("赵六",18));
//使用keySet加增强for遍历Map集合
Set<String> set = map.keySet();
for (String key : set) {
Person value = map.get(key);
System.out.println(key+"-->"+value);
}
}
}
9.5 HashTable
java.util.HashTable
- 与HashMap的区别:
① 线程
HashTable:底层是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢。
HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
② null
HashTable:不能存储null值、null键
HashMap(以及之前学的所有集合):可以存储null值、null键
- 过时:
HashTable 和 Vector 一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了。
但是HashTable的子类Properties依然活跃,Properties集合是一个唯一和IO流相结合的集合。
十、练习
10.1 斗地主
public class Dou {
public static void main(String[] args) {
ArrayList<String> card = saveCard();
// System.out.println(card.size());
// System.out.println(card);
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
ArrayList<String> bottom = new ArrayList<>();
deliverCard(player1,player2,player3,bottom,card);
System.out.println("刘德华:" + player1);
System.out.println("周星驰:" + player2);
System.out.println("古天乐:" + player3);
System.out.println("底牌:" + bottom);
// showCard(player1);
// showCard(player2);
// showCard(player3);
// showCard(bottom);
}
//存牌并打乱
public static ArrayList<String> saveCard(){
ArrayList<String> card = new ArrayList<>();
String[] color = {"♥","♦","♣","♠"};
String[] tag = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};
for (int i = 0; i < color.length; i++) {
for (int j = 0; j < tag.length; j++) {
card.add(color[i] + tag[j]);
}
}
card.add("大王");
card.add("小王");
Collections.shuffle(card);//随机打乱集合中的元素
return card;
}
//发牌
public static void deliverCard(ArrayList<String> player1,ArrayList<String> player2,ArrayList<String> player3,ArrayList<String> bottom,ArrayList<String> card){
for (int i = 0; i < card.size(); i++) {
if(i > 50){
bottom.add(card.get(i));
}
else{
if(i % 3 == 0){
player1.add(card.get(i));
}
if(i % 3 == 1){
player2.add(card.get(i));
}
if(i % 3 == 2){
player3.add(card.get(i));
}
}
}
}
//看牌
public static void showCard(ArrayList<String> cardlist){
for (int i = 0; i < cardlist.size(); i++) {
System.out.print(cardlist.get(i) + "\t\t");
}
System.out.println();
}
}
10.2 字符个数
计算一个字符串中的每个字符个数
public class CalcuChar {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String s = sc.nextLine();
HashMap<Character,Integer> map = new HashMap<>();
char[] charArray = s.toCharArray();
for (int i = 0; i < charArray.length; i++) {
if(map.containsKey(charArray[i])){
map.put(charArray[i],map.get(charArray[i]) + 1);
}
else map.put(charArray[i],1);
}
// Set<Map.Entry<Character,Integer>> en = map.entrySet();
for (Map.Entry<Character,Integer> en:
map.entrySet()) {
System.out.print(en.getKey() + ":");
System.out.print(en.getValue());
System.out.println();
}
}
}
10.3 斗地主升级版
/*
斗地主综合案例:有序版本
1.准备牌
2.洗牌
3.发牌
4.排序
5.看牌
*/
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(List)
*/
Collections.shuffle(pokerIndex);
//System.out.println(pokerIndex);
/*
3.发牌
*/
//定义4个集合,存储玩家牌的索引,和底牌的索引
ArrayList<Integer> player01 = new ArrayList<>();
ArrayList<Integer> player02 = new ArrayList<>();
ArrayList<Integer> player03 = 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发牌
player01.add(in);
}else if(i%3==1){
//给玩家2发牌
player02.add(in);
}else if(i%3==2){
//给玩家3发牌
player03.add(in);
}
}
/*
4.排序
使用Collections中的方法sort(List)
默认是升序排序
*/
Collections.sort(player01);
Collections.sort(player02);
Collections.sort(player03);
Collections.sort(diPai);
/*
5.看牌
调用看牌的方法
*/
lookPoker("刘德华",poker,player01);
lookPoker("周润发",poker,player02);
lookPoker("周星驰",poker,player03);
lookPoker("底牌",poker,diPai);
}
/*
定义一个看牌的方法,提高代码的复用性
参数:
String name:玩家名称
HashMap<Integer,String> poker:存储牌的poker集合
ArrayList<Integer> list:存储玩家和底牌的List集合
查表法:
遍历玩家或者底牌集合,获取牌的索引
使用牌的索引,去Map集合中,找到对应的牌
*/
public 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();//打印完每一个玩家的牌,换行
}
}
十一、JDK9的新特性
List、Set、Map接口添加了一个静态方法of,可以给集合一次性添加多个元素。
static <E> List<E> of (E...elements)
使用前提: 当集合中存储的元素的个数已经确定了,不再改变时使用。
注意:
① of 方法只适用于List接口,Set接口,Map接口,不适用于这些接口的实现类。
② of 方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会出现异常。
③ Set接口和Map接口在调用方法时,不能有重复的元素,否则会抛出异常。
public class Demo01JDK9 {
public static void main(String[] args) {
List<String> list = List.of("a", "b", "a", "c", "d");
System.out.println(list);//[a, b, a, c, d]
//list.add("w");//UnsupportedOperationException:不支持操作异常
//Set<String> set = Set.of("a", "b", "a", "c", "d");//IllegalArgumentException:非法参数异常,有重复的元素
Set<String> set = Set.of("a", "b", "c", "d");
System.out.println(set);
//set.add("w");//UnsupportedOperationException:不支持操作异常
//Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20,"张三",19);////IllegalArgumentException:非法参数异常,有重复的元素
Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20);
System.out.println(map);//{王五=20, 李四=19, 张三=18}
//map.put("赵四",30);//UnsupportedOperationException:不支持操作异常
}
}
十二、Debug调试
使用方式:
在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里),右键,选择Debug执行程序,程序就会停留在添加的第一个断点处。
执行程序:
- f8:逐行执行程序
- f7:进入到方法中
- shift+f8:跳出方法
- f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
- ctrl+f2:退出debug模式,停止程序
- Console:切换到控制台