一、背景

最近在学习数据结构和算法的过程中频繁用到了Collections工具类,这是开发中的一把利器,简化了许多涉及集合的编码,该文将通过实例对此工具类进入深入剖析。

二、概念

1、定义

java.util.Collections

是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的集合框架。

public class Collections {
// 默认构造方法私有化,不允许实例化.
private Collections() {
}
...
}
2、方法

Collections的方法都为静态方法,主要分为以下几类:该文主要对排序查找/替换等方法进行解析。

2.1、排序方法
  • 方法定义:
// 反转
public static void reverse(List<?> list)
// 随机排序
public static void shuffle(List<?> list)
// 按自然排序的升序排序
public static <T> void sort(List<T> list, Comparator<? super T> c)
// 交换两个索引位置的元素
public static void swap(List<?> list, int i, int j)
// 旋转
public static void rotate(List<?> list, int distance)
2.2、查找/替换方法
// 二分查找
int binarySearch(List<? extends Comparable<? super T>> list, T key)
// 根据定制排序,返回最大元素
int max(Collection coll, Comparator c)
// 根据定制排序,返回最小元素
int min(Collection coll, Comparator c)
// 统计元素出现次数
int frequency(Collection c, Object o),统计元素出现次数
// 统计targe在list中第一次出现的索引
int indexOfSubList(List list, List target)
// 用新元素替换旧元素
boolean replaceAll(List list, Object oldVal, Object newVal)

三、斗地主实例

3.1、代码结构

3.2、常量定义
  • 用集合的方式定义扑克牌的花色、牌面数字、大小王。
/**
* 扑克牌常量定义
* * @author zhuhuix
* @date 2020-06-05
*/
public class Constant { // 纸牌花色:黑桃,红心,梅花,方块
final static List<String> COLORS = new ArrayList<>(
Arrays.asList(new String[]{"♢", "", "♡", ""}));
// 牌面数字
final static List<String> NUMBERS = new ArrayList<>(
Arrays.asList(new String[]{"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"}));
// 大王小王
final static List<String> JOKER = new ArrayList<>(
Arrays.asList(new String[]{"小王","大王"}));
}
3.3、单只牌类
  • 在单只牌类的定义中,重写了会影响到牌面大小的compareTo比较方法:

    -- 如果是""的两只牌的比较,则"大王"大于"小王";

    -- 如果是""与“数字牌”之间的比较,则""大于“数字牌”;

    -- 如果是“数字牌”相互之间的比较,数字大的牌则牌面大,如果数字相同,则按花色比较(♢<< ♡< )(虽然斗地主不按花色排列大小,但程序会按花色大小进行理牌)。
/**
* 单只牌
* * @author zhuhuix
* @date 2020-06-05
*/
public class Card implements Comparable { // 花色
private String color = "";
//数字
private String number = ""; public Card() {
} public Card(String color, String number) {
this.color = color;
this.number = number;
} public String getColor() {
return this.color;
} public void setColor(String color) {
this.color = color;
} public String getNumber() {
return this.number;
} public void setNumber(String number) {
this.number = number;
} @Override
public String toString() {
return this.color + this.number;
} @Override
public int compareTo(Object o) {
if (o instanceof Card) {
int thisColorIndex = Constant.COLORS.indexOf(this.getColor());
int anotherColorIndex = Constant.COLORS.indexOf(((Card) o).getColor());
int thisNumberIndex = Constant.NUMBERS.indexOf(this.getNumber());
int anotherNumberIndex = Constant.NUMBERS.indexOf(((Card) o).getNumber()); // 大小王之间相互比较: 大王大于小王
if ("JOKER".equals(this.color) && "JOKER".equals(((Card) o).getColor())) {
return thisColorIndex > anotherColorIndex ? 1 : -1;
} // 大小王与数字牌之间相互比较:大小王大于数字牌
if ("JOKER".equals(this.color) && !"JOKER".equals(((Card) o).getColor())) {
return 1;
}
if (!"JOKER".equals(this.color) && "JOKER".equals(((Card) o).getColor())) {
return -1;
} // 数字牌之间相互比较: 数字不相等,数字大则牌面大;数字相等 ,花色大则牌面大
if (thisNumberIndex == anotherNumberIndex) {
return thisColorIndex > anotherColorIndex ? 1 : -1;
} else {
return thisNumberIndex > anotherNumberIndex ? 1 : -1;
} } else {
return -1;
}
}
}
3.4、玩家类
  • 玩家类中主要定义了抓牌、洗牌、理牌、找牌、获取最大最小牌、统计炸弹数等成员方法,在这些成员方法中,我们广泛应用了Collections工具类的静态方法
/**
1. 玩家
2. * @author zhuhuix
3. @date 2020-06-05
*/
public class Player { // 玩家姓名
private String name; // 玩家类型:农民/地主
private String type; // 抓到的牌
private List<Card> cards; public Player(String name, String type) {
this.name = name;
this.type = type;
this.cards = new ArrayList<>();
} // 洗牌 shuffle
public void shuffle() {
Collections.shuffle(this.cards);
} // 理牌 sort
public void sort() {
Collections.sort(this.cards, Card::compareTo);
} // 抓牌
public void draw(Card card) {
this.cards.add(card);
} // 出牌
public void play(Card card) {
this.cards.remove(card);
} // 找出最大牌 max
public Card max() {
return Collections.max(this.cards, Card::compareTo);
} // 找出最小牌 min
public Card min() {
return Collections.min(this.cards, Card::compareTo);
} // 找到指定牌的位置 binarySearch
public int binarySearch(Card card) {
return Collections.binarySearch(this.cards, card, Card::compareTo);
} // 统计有几手炸弹 frequency
public int frequency() {
int count = 0;
List<String> numbers= new ArrayList<>();
List<String> colors= new ArrayList<>();
for (int i = 0; i < this.cards.size(); i++) {
colors.add(this.cards.get(i).getColor());
numbers.add(this.cards.get(i).getNumber());
}
for (int j = 0; j < Constant.NUMBERS.size(); j++) {
if (Collections.frequency(numbers, Constant.NUMBERS.get(j)) == 4) {
count++;
}
}
if (Collections.frequency(colors, "JOKER") == 2) {
count++;
}
return count;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getType() {
return type;
} public void setType(String type) {
this.type = type;
} public List<Card> getCards() {
return cards;
} public void setCards(List<Card> cards) {
this.cards = cards;
} @Override
public String toString() {
StringBuilder poker = new StringBuilder("[");
Iterator<Card> iterator = this.cards.iterator();
while (iterator.hasNext()) {
poker.append(iterator.next().toString() + ",");
}
poker.setCharAt(poker.length() - 1, ']');
return this.getType() + ":" + this.getName() + "拿到" + this.cards.size() + "张牌:" + poker;
}
3.5、主程序
  1. 生成一整副牌;
  2. 设置3个玩家,其中两个为农民,一个为地主;
  3. 3人轮流抓牌,地主多拿三张牌;
  4. 玩家理牌看牌(找到最大牌最小牌);
  5. 判断大王是否在地主手上?
  6. 统计各个玩家手上有几个炸弹?
/**
* 斗地主的主程序
*
* @author zhuhuix
* @date 2020-6-5
*/
public class PlayDemo { public static void main(String[] args) { // 生成一副扑克牌
Poker poker = new Poker();
System.out.println("扑克牌共" + poker.getCardCount() + "只"); // 设置三个玩家,并设定两人为农民,一个为地主
int playCount = 3;
Player player1 = new Player("玩家1", "农民");
Player player2 = new Player("玩家2", "农民");
Player player3 = new Player("玩家3", "地主"); // 三个玩家按顺序抓牌
int i;
for (i = 0; i < poker.getCardCount() - playCount; i++) {
if (i % playCount == 0) {
player1.draw(poker.getCards().get(i));
} else if (i % playCount == 1) {
player2.draw(poker.getCards().get(i));
} else if (i % playCount == 2) {
player3.draw(poker.getCards().get(i));
}
} // 地主拿剩余底牌
while (i < poker.getCardCount()) {
player3.draw(poker.getCards().get(i));
i++;
} // 展示三个玩家洗牌后手上的牌面及最大和最小的牌
player1.sort();
System.out.println(player1.toString());
System.out.println("最大牌是:"+player1.max().toString()+",最小牌是:"+player1.min().toString());
player2.sort();
System.out.println(player2.toString());
System.out.println("最大牌是:"+player2.max().toString()+",最小牌是:"+player2.min().toString());
player3.sort();
System.out.println(player3.toString());
System.out.println("最大牌是:"+player3.max().toString()+",最小牌是:"+player3.min().toString()); // 大王是否在地主手里
if (player3.binarySearch(new Card("JOKER","大王"))>=0){
System.out.println("大王在"+player3.getType()+player3.getName()+"手里");
} // 统计有几手炸弹
System.out.println(player1.getName()+"手上有"+player1.frequency()+"手炸弹");
System.out.println(player2.getName()+"手上有"+player2.frequency()+"手炸弹");
System.out.println(player3.getName()+"手上有"+player2.frequency()+"手炸弹");
}
}

程序输出如下:

四、深入理解

  • 我们对其中的一些方法进行源码跟踪

    -- shuffle
 public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
//将集合转化成数组
Object arr[] = list.toArray(); // 通过随机数随机交换数组元素位置
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
// 通过迭代器将打乱顺序的数组赋值给集合
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}

-- sort

public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
...
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
//调用数组工具类的排序方法--该方法为改进过的归并排序
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}

-- min/max

public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
if (comp==null)
return (T)min((Collection) coll); Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
// 通过迭代器循环比较,找到最小的
while (i.hasNext()) {
T next = i.next();
if (comp.compare(next, candidate) < 0)
candidate = next;
}
return candidate;
} public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) {
if (comp==null)
return (T)max((Collection) coll); Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
// 通过迭代器循环比较,找到最大的
while (i.hasNext()) {
T next = i.next();
if (comp.compare(next, candidate) > 0)
candidate = next;
}
return candidate;
}

-- binarySearch

public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) {
if (c==null)
return binarySearch((List<? extends Comparable<? super T>>) list, key); if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key, c);
else
return Collections.iteratorBinarySearch(list, key, c);
}
...
// 二分查找法
private static <T> int iteratorBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
int low = 0;
int high = l.size()-1;
ListIterator<? extends T> i = l.listIterator(); while (low <= high) {
int mid = (low + high) >>> 1;
T midVal = get(i, mid);
int cmp = c.compare(midVal, key); if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}

用斗地主的实例学会使用java Collections工具类的更多相关文章

  1. JAVA Collections工具类sort()排序方法

    主要分析内容: 一.Collections工具类两种sort()方法 二.示例 一.Collections工具类两种sort()方法 格式一: public static <T extends ...

  2. java Collections工具类

    Collections 是专门对集合进行操作的类  比如排序sort 也可以使用自定义的比较器 sort文档中的定义 必须具有比较性,具有比较性必须是comparable 的子类 '<T ext ...

  3. (Set, Map, Collections工具类)JAVA集合框架二

    Java集合框架部分细节总结二 Set 实现类:HashSet,TreeSet HashSet 基于HashCode计算元素存放位置,当计算得出哈希码相同时,会调用equals判断是否相同,相同则拒绝 ...

  4. Map集合、HashMap集合、LinkedHashMap集合、Hashtable集合、Collections工具类和模拟斗地主洗牌和发牌

    1.Map集合概述和特点 * A:Map接口概述  * 查看API可以知道:          * 将键映射到值的对象          * 一个映射不能包含重复的键          * 每个键最多 ...

  5. Java:集合,Collections工具类用法

    Collections工具类提供了大量针对Collection/Map的操作,总体可分为四类,都为静态(static)方法: 1. 排序操作(主要针对List接口相关) reverse(List li ...

  6. Java精选笔记_集合概述(Collection接口、Collections工具类、Arrays工具类)

    集合概述 集合有时又称为容器,简单地说,它是一个对象,能将具有相同性质的多个元素汇聚成一个整体.集合被用于存储.获取.操纵和传输聚合的数据. 使用集合的技巧 看到Array就是数组结构,有角标,查询速 ...

  7. Java集合框架:Collections工具类

    java.util.Collections工具类提供非常多实用的方法.使得程序员操作集合类的时候更加的方便easy,这些方法都是静态的. 整个Collections工具类源代码几乎相同有4000行.我 ...

  8. Java集合——Collections工具类

    Java集合——Collections工具类 摘要:本文主要学习了Collections工具类的常用方法. 概述 Collections工具类主要用来操作集合类,比如List和Set. 常用操作 排序 ...

  9. Java从入门到放弃18---Map集合/HashMap/LinkedHashMap/TreeMap/集合嵌套/Collections工具类常用方法

    Java从入门到放弃18—Map集合/HashMap/LinkedHashMap/TreeMap/集合嵌套/Collections工具类常用方法01 Map集合Map集合处理键值映射关系的数据为了方便 ...

随机推荐

  1. 两个有序数组 A1 A2 的合并

    /** * 问题6.有序数组 A1 A2 的合并 */ @Test public void orderArrayMerge() { // 两个有序数组 A1 A2 的合并 int[] A1 = {1, ...

  2. Holy Grail Bellman-Ford/spfa

    Holy Grail Bellman-Ford #include <bits/stdc++.h> using namespace std; , maxm = ; const int inf ...

  3. kube-controller-manager反复重启解决

    背景 ​ 某环境,kube-controller-manager反复重启,尝试重建kube-controller-manager的pod,但是过一会问题复现. 如上图,kube-controller- ...

  4. 博客营销(Blog Marketing)

    一.什么是博客营销 博客营销(Blog Marketing)的概念可以说并没有严格的定义,简单来说,就是利用博客这种网络应用形式开展网络营销.要说明什么是博客营销,首先要从什么是博客说起. 博客(Bl ...

  5. 一文讲透Modbus协议

    前言 Modbus是一种串行通讯协议,是Modicon公司(现在的施耐德电气 Schneider Electric) 于1979年为使用可编程逻辑控制器(PLC)通信而发表.Modbus已经成为工业领 ...

  6. JS最通俗易懂简易轮播实现

    轮播图作为前端比较简易的动画,使用非常频繁,这里记录以便使用 此轮播图为最简易自动播放,非无缝,无按钮,无缩略图和序号 想看全套轮播图可以查看我的分类轮播图全套 html 布局 <div sty ...

  7. Verilog代码和FPGA硬件的映射关系(五)

    既然我们可以指定寄存器放在IOB内,那我们同样也可以指定PLL的位置.首先要确保我们有多个PLL才行.如图1所示,我们所使用的EP4CE10F17C8芯片刚好有两个. 图 1 为了演示这个例子,我们使 ...

  8. [JavaWeb基础] 026.JAVA中使用Axis搭建webservice-环境搭建(一)

    在实际的项目开发过程中,我们经常会使用第三方交互,特别是在前后端语言不一致的情况下,相信webservice这个第三方控件大家都清楚.后面会慢慢带大家来学习它的使用方式,下面就先讲讲它的工具搭建. 一 ...

  9. [SD心灵鸡汤]005.每月一则 - 2015.09

    精彩的激励人生的话都是从成功者嘴里说出来的,他们成功的过程我们仅仅知道一二,结果却是名满天下.既然看这个激励语,就是想要成功的人,所以大家好好读懂,然后执行,那么你离成功就不远了! 1.万里寻山历百艰 ...

  10. 01 . Prometheus简介及安装配置Grafana

    Promethus简介 Prometheus受启发于Google的Brogmon监控系统(相似的Kubernetes是从Google的Brog系统演变而来),从2012年开始由前Google工程师在S ...