一、前言
<font face=黑体>因为明年三四月份想换工作,也为了对 Java 语言有更深的了解,所以想从新学一遍 Java,把以前没有留神到的细节再坚固一下,因为当初工夫还是有的,所以我决定从新的过一遍 Java 的知识点(至多比粗犷的刷 Java 面试题好)。我这里筹备的学习材料次要有十大章,咱们来看一下每章的目录名称(用的 Java 版本是目前用的最多的版本 Java 8):
- Java 根底语法;
- 面向对象和封装;
- 罕用 API 第一局部;
- 继承与多态;
- 罕用 API 第二局部;
- 汇合;
- 异样与多线程;
- File 类与 IO 流;
- 网络编程;
- JDK 8 新个性。
<font face=黑体>然而我不打算从第一章开始看,我决定从第 6 章 汇合 开始,等 6 到 10 章学完,再学 1 到 5 章,咱们来看一下汇合这一章的目录:
- Collection 汇合;
- 泛型;
- 综合案例 1;
- List 汇合;
- Set 汇合;
- Collections 工具类;
- Map 汇合;
- 综合案例 2;
<font face=黑体>汇合这一章的内容的确有点多,所以咱们分三局部来解说,让咱们开始。
二、Collection 汇合
2.1、汇合概述
<font face=黑体>汇合是 Java 中提供的一种容器,能够用来存储多个数据。汇合和数组都是容器,它们的区别如下:
- <font face=黑体>数组的长度是固定的,汇合的长度是可变的。
- <font face=黑体>数组中存储的是对立类型的元素,能够存储根本数据类型,也能够存储对象。汇合存储的都是对象,不能够存储根本数据类型,而且对象的类型能够不统一。
2.2、汇合框架
<font face=黑体>汇合的框架如下所示,须要留神的点有:
- <font face=黑体>TreeSet 与 HashSet 是无序的,即存和取的元素的程序有可能不统一,然而 LinkedHashSet 是有序的。
- <font face=黑体>顶层不是接口就是抽象类,无奈创建对象应用,须要底层的子类创建对象应用。
2.3、Collection 汇合罕用性能
<font face=黑体>Collection 是所有单列汇合的父接口,因而在 Collection 中定义了单列汇合(List 和 Set)通用的一些办法,这些办法可用于操作所有的单列汇合,办法如下:
- <font face=黑体>public boolean add(E e):把给定的对象增加到以后汇合中。
- <font face=黑体>public void clear():清空集合中的所有元素。
- <font face=黑体>public boolean remove(E e):把给定的对象在以后汇合中删除。
- <font face=黑体>public boolean contains(E e):判断以后汇合中是否蕴含给定的对象。
- <font face=黑体>public boolean isEmpty():判断以后汇合是否为空。
- <font face=黑体>public int size():返回汇合中元素个数。
- <font face=黑体>public Object[] toArray():把汇合转化成数组。
<font face=黑体>Collection 罕用性能代码演示如下所示,输入后果大家能够本人复制到 Intellij IDEA 中查看。
public class CollectionDemo01 { public static void main(String[] args) { // 创立汇合对象 Collection<String> coll = new ArrayList<>(); System.out.println(coll); // 重写了toSting() 办法 /** * public boolean add(E e):把给定的对象增加到以后汇合中。 * 返回值是一个 boolean 值,个别都返回 true,能够不必接管 */ boolean b1 = coll.add("张三"); System.out.println("b1:" + b1); // b1:true System.out.println(coll); // [张三] coll.add("李四"); coll.add("王五"); coll.add("赵六"); coll.add("田七"); System.out.println(coll); // [张三, 李四, 王五, 赵六, 田七] System.out.println("---------------------分割线-----------------------"); System.out.println(); /** * public boolean remove(E e):把给定的对象在以后汇合中删除。 * 返回值是一个 boolean 值,汇合中存在元素,删除元素,返回 true,汇合中不存在的话,删除失败,返回 false */ boolean b2 = coll.remove("赵六"); System.out.println("b2:" + b2); // b2:true boolean b3 = coll.remove("赵四"); System.out.println("b3:" + b3); // b3:false System.out.println(coll); // [张三, 李四, 王五, 田七] System.out.println("---------------------分割线-----------------------"); System.out.println(); /** * public boolean contains(E e):判断以后汇合中是否蕴含给定的对象。 * 蕴含返回 true,不蕴含返回 false */ boolean b4 = coll.contains("李四"); System.out.println("b4:" + b4); // b4:true boolean b5 = coll.contains("赵四"); System.out.println("b5:" + b5); // b5:false System.out.println("---------------------分割线-----------------------"); System.out.println(); /** * public boolean isEmpty():判断以后汇合是否为空。 */ boolean b6 = coll.isEmpty(); System.out.println("b6:" + b6); // b6:false System.out.println("---------------------分割线-----------------------"); System.out.println(); /** * public int size():返回汇合中元素个数。 */ int size = coll.size(); System.out.println("size:" + size); System.out.println("---------------------分割线-----------------------"); System.out.println(); /** * public Object[] toArray():把汇合转化成数组。 */ Object[] arr = coll.toArray(); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } System.out.println("---------------------分割线-----------------------"); System.out.println(); /** * public void clear():清空集合中的所有元素。 * 然而不删除汇合,汇合还存在 */ coll.clear(); System.out.println(coll); // [] System.out.println(coll.isEmpty()); // true }}
三、Iterator 迭代器
3.1、Iterator 接口概述
<font face=黑体>在程序开发中,常常须要遍历汇合中的元素,针对这种需要,JDK 专门提供了一个接口 Iterator。Iterator 接口也是 Java 汇合中的一员,次要用于迭代拜访(即遍历)Collection 中的元素,因为 Iterator 对象也被称为迭代器,是一种通用的取出汇合中元素的形式。
3.2、Iterator 接口罕用办法
<font face=黑体>罕用办法有一下两个:
- <font face=黑体>public boolean hasNext():如果仍有元素,则返回 true。
- <font face=黑体>public E next():返回迭代的下一个元素。
3.3、迭代器的应用步骤
<font face=黑体>因为 Iterator 迭代器是一个接口,咱们无奈间接应用,须要应用 Iterator 接口的实现类对象,通过 Collection 接口中的 iterator() 办法返回迭代器的实现类对象。应用步骤如下:
- <font face=黑体>应用汇合中的 iterator() 办法取得迭代器的实现类对象,应用 Iterator 接口接管;
- <font face=黑体>应用 Iterator 中的办法 hasNext() 判断还有没有下一个元素;
- <font face=黑体>应用 Iterator 中的办法 next() 取出汇合中的元素。
<font face=黑体>留神:Iterator 接口也是有泛型的,迭代器的泛型跟着汇合走,汇合是什么泛型,迭代器就是什么泛型。
3.4、加强 for 循环
<font face=黑体>加强 for 循环(也称 forEach 循环)是 JDK 1.5当前进去的一个高级 for 循环,专门用来遍历数组和汇合,它的外部原理其实是个 Iterator 迭代器,所以在遍历的过程中,不能对汇合中的元素进行增删操作。
<font face=黑体>格局:for(汇合/数组的数据类型 变量名 : 汇合名/数组名)
<font face=黑体>for(int i : arr)
<font face=黑体>Iterator 和加强 for 循环遍历汇合代码演示如下所示,输入后果大家能够本人复制到 Intellij IDEA 中查看。
public class IteratorDemo02 { public static void main(String[] args) { // 创立汇合对象 Collection<String> coll = new ArrayList<>(); coll.add("乔丹"); coll.add("詹姆斯"); coll.add("奥尼尔"); coll.add("艾佛森"); coll.add("科比"); /** * 1、应用汇合中的 iterator() 办法取得迭代器的实现类对象,应用 Iterator 接口接管; * 留神:Iterator<E> 接口也是有泛型的,迭代器的泛型跟着汇合走,汇合是什么泛型,迭代器就是什么泛型 * 2、应用 Iterator 中的办法 hasNext() 判断还有没有下一个元素 * 3、应用 Iterator 中的办法 next() 取出汇合中的元素。 */ Iterator<String> it = coll.iterator(); while (it.hasNext()) { System.out.println(it.next()); } System.out.println("---------------------分割线-----------------------"); System.out.println(); // 利用 for 循环改写 while 循环 for ( Iterator<String> it1 = coll.iterator();it1.hasNext();) { System.out.println(it1.next()); } System.out.println("---------------------分割线-----------------------"); System.out.println(); // 能够用加强 for 循环遍历(不能用一般 for 循环遍历) for (String s : coll) { System.out.println(s); } }}
3.5、迭代器的工作原理
- <font face=黑体>Iterator<String> it = coll.iterator():获取迭代器的实现类对象,并把援用(能够了解成指针)指向汇合中的 -1 索引;
- <font face=黑体>it.hasNext():判断汇合中还有没有下一个元素;
- <font face=黑体>it.next():取出下一个元素,并把指针(这里用指针来阐明好了解一点)向后挪动一位。
四、泛型
4.1、泛型概述
<font face=黑体>泛型是一种未知的数据类型,当咱们不晓得用什么数据类型的时候,能够应用泛型,泛型也能够看成是一个变量,用来接收数据类型。ArrayList 汇合在定义的时候(源码中就是利用泛型的),不晓得汇合中都会存储什么类型的数据,所以应用泛型。
4.2、应用泛型的长处与弊病
<font face=黑体>汇合不应用泛型,默认的类型就是 Object 类型,能够存储任意类型的数据,然而同时也使得汇合变得不平安,容易引发异样,所有应用泛型的长处有:
- <font face=黑体>防止了类型转化的麻烦;
- <font face=黑体>把运行期异样(代码运行之后会抛出的异样),晋升到了编译期(写代码的时候就会报错)。
<font face=黑体>应用泛型创立汇合和不应用泛型创立汇合代码演示如下所示,输入后果大家能够本人复制到 Intellij IDEA 中查看。
public class GenericDemo01 { public static void main(String[] args) { // 不应用泛型 //show01(); // 应用泛型 show02(); } /** * 创立汇合对象,不应用泛型 * 益处: * 汇合不应用泛型,默认的类型就是 Object 类型,能够存储任意类型的数据 * 弊病: * 不平安,容易引发异样 */ private static void show01() { ArrayList list = new ArrayList(); list.add("abc"); list.add(1); // 应用迭代器遍历 Iterator it = list.iterator(); while (it.hasNext()) { Object obj = it.next(); System.out.println(obj); String s = (String) obj; // 运行后,会有异样 System.out.println(s.length()); // java.lang.ClassCastException: Integer cannot be cast to String } } /** * 创立汇合对象,应用泛型 * 益处: * 1、防止了类型转化的麻烦 * 2、把运行期异样(代码运行之后会抛出的异样),晋升到了编译期(写代码的时候就会报错) * 弊病: * 泛型是什么类型,只能存储什么类型的数据 */ private static void show02() { ArrayList<String> list = new ArrayList<>(); list.add("abc"); // 应用迭代器遍历 Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); System.out.println(s); System.out.println(s.length()); } }}
4.3、定义含有泛型的类
<font face=黑体>含有泛型的类定义如下代码所示:
public class GenericDemo02<E> { private E name; public E getName() { return name; } public void setName(E name) { this.name = name; } public static void main(String[] args) { GenericDemo02<String> g1 = new GenericDemo02(); g1.setName("testGeneric"); System.out.println(g1.getName()); GenericDemo02<Integer> g2 = new GenericDemo02(); g2.setName(123); System.out.println(g2.getName()); }}
4.4、定义含有泛型的办法
<font face=黑体>定义含有泛型的办法,泛型须要定义在办法的修饰符和返回值类型之间,定义格局如下所示:
修饰符 <泛型> 返回值类型 办法名(参数列表(应用泛型))
public <E> void method01(E e) { System.out.println(e);}// 静态方法public static <E> void method2(E e) { System.out.println(e);}
4.5、定义并应用含有泛型的接口
<font face=黑体>含有泛型的接口如下所示:
public interface GenericInterface04<I> { public abstract void method(I i);}
<font face=黑体>含有泛型的接口的应用形式有两种:
<font face=黑体>在定义接口的实现类的时候指定接口的泛型。
public class GenericInterface04Impl1 implements GenericInterface04<String> { @Override public void method(String s) { System.out.println(s); }}
<font face=黑体>接口应用什么泛型,实现类就应用什么泛型,类跟着接口走。就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型;
public class GenericInterface04Impl2<I> implements GenericInterface04<I> { @Override public void method(I i) { System.out.println(i); }}
4.6、泛型通配符
<font face=黑体>当应用泛型类或者接口时,传递的数据中,泛型类型不确定,能够通过通配符 <?> 示意,然而应用通配符只能作为办法的参数传递,不能定义对象。泛型通配符的应用如下所示:
public class GenericDemo05 { public static void main(String[] args) { ArrayList<Integer> list1 = new ArrayList<>(); list1.add(1); list1.add(2); ArrayList<String> list2 = new ArrayList<>(); list2.add("a"); list2.add("b"); printArray(list1); printArray(list2); } public static void printArray(ArrayList<?> list) { Iterator<?> iterator = list.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } }}
4.7、受限泛型
<font face=黑体>泛型的下限限定:
<font face=黑体>格局:类型名称 <? extends E> 对象名称
<font face=黑体>意义:只能承受 E 类型及其子类。
<font face=黑体>泛型的上限限定:
<font face=黑体>格局:类型名称 <? super E> 对象名称
<font face=黑体>意义:只能承受 E 类型及其父类。
<font face=黑体>受限泛型代码演示如下所示,大家能够本人复制到 Intellij IDEA 中查看。
public class GenericDemo06 { public static void main(String[] args) { Collection<Integer> list1 = new ArrayList<>(); Collection<String> list2 = new ArrayList<>(); Collection<Number> list3 = new ArrayList<>(); Collection<Object> list4 = new ArrayList<>(); /** * Integer extends Number extends Object * String extends Object */ getElement1(list1); getElement1(list2); // 报错 getElement1(list3); getElement1(list4); // 报错 getElement2(list1); // 报错 getElement2(list2); // 报错 getElement2(list3); getElement2(list4); } // 泛型的下限:此时的泛型?,必须是 Number 类型或者是 Number 类型的子类 public static void getElement1(Collection<? extends Number> coll) { } // 泛型的上限:此时的泛型?,必须是 Number 类型或者是 Number 类型的父类 public static void getElement2(Collection<? super Number> coll) { }}
五、汇合综合案例——斗地主
<font face=黑体>综合案例步骤:
- <font face=黑体>筹备牌:
54 张牌存储到一个汇合中;
非凡牌:大王,小王;
其余 52 张牌:
定义一个数组,存储 4 种花色 $\color{red}{♥ ♦}$ $\color{black}{♠ ♣}$;
定义一个数组,存储 13 个序号[2、A、K...3];
循环嵌套遍历下面两个数组,组装 52 张牌[$\color{red}{♥2}$,$\color{red}{♦A}$,$\color{black}{♥K}$,$\color{black}{♣Q}$,...];
- <font face=黑体>洗牌
利用汇合工具类 Collections.shuffle() 来随机打乱汇合中元素的地位;
- <font face=黑体>发牌
发牌要求如下:
一人 17 张牌,残余 3 张作为底牌,一人一张轮流发牌(汇合的索引 % 3);
定义四个汇合,存储 3 个玩家的牌和底牌;
- <font face=黑体>看牌
间接打印汇合,遍历存储玩家和底牌的汇合;
<font face=黑体>具体实现代码如下所示:
public class DouDiZhu { public static void main(String[] args) { // 1、筹备牌 // 定义一个存储 54 张牌的汇合; 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) { // 把组装好的牌存到poker汇合中 poker.add(color + number); } } // 2、洗牌 // 利用汇合工具类 Collections.shuffle() 来随机打乱汇合中元素的地位; Collections.shuffle(poker); // 3、发牌 // 定义四个汇合,存储 3 个玩家的牌和底牌; ArrayList<String> player01 = new ArrayList<>(); ArrayList<String> player02 = new ArrayList<>(); ArrayList<String> player03 = new ArrayList<>(); ArrayList<String> dipai = new ArrayList<>(); // 4、遍历poker汇合,获取每一种牌 // 应用poker汇合的索引 % 3 给三个玩家轮流发牌,最初残余三张牌给底牌 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 { player03.add(p); } } // 不便起见间接打印 System.out.println("玩家1的牌:" + player01); System.out.println("玩家2的牌:" + player02); System.out.println("玩家3的牌:" + player03); System.out.println("底牌:" + dipai); }}
<font face=黑体>打印后果如下所示:
六、小结
<font face=黑体>汇合第一局部中咱们讲了 Collection汇合接口、Iterator 迭代器、泛型和斗地主综合案例,下一节咱们讲数据结构、List 汇合和 Set 汇合。
七、源码
<font face=黑体>文章中用到的所有源码已上传至 github,有须要的能够去下载。