Map

primary coverage

Learning objectives

Chapter 1 map set

1.1 general

In real life, we often see such a collection: IP address and host name, ID number and personal, system user name and system user object, this one-to-one correspondence, is called mapping. Java provides a special collection class to store the object of this object relationship, that is, Java util. Map interface.

By looking at the description of the map interface, we find that the collections under the map interface and the collections under the collection interface store data in different forms, as shown in the following figure.

1.2 common subclasses of map

By viewing the map interface description, we can see that there are multiple subclasses of map. Here we mainly explain the commonly used HashMap sets and LinkedHashMap sets.

1.3 common methods in map interface

Many methods are defined in the map interface. The common methods are as follows:

Method demonstration of map interface

public class MapDemo {
    public static void main(String[] args) {
        //创建 map对象
        HashMap<String,String>  map = new HashMap<String,String>();

        //添加元素到集合
        map.put("黄晓明","杨颖");
        map.put("文章","马伊琍");
        map.put("邓超","孙俪");
        System.out.println(map);

        //String remove(String key)
        System.out.println(map.remove("邓超"));
        System.out.println(map);

        // 想要查看 黄晓明的媳妇 是谁
        System.out.println(map.get("黄晓明"));
        System.out.println(map.get("邓超"));    
    }
}

1.4 map set traversal key value finding method

Key value finding method: obtain the value corresponding to the key through the key in the element

Analysis steps:

Code demonstration:

public class MapDemo01 {
    public static void main(String[] args) {
        //创建Map集合对象 
        HashMap<String,String> map = new HashMap<String,String>();
        //添加元素到集合 
        map.put("胡歌","霍建华");
        map.put("郭德纲","于谦");
        map.put("薛之谦","大张伟");

        //获取所有的键  获取键集
        Set<String> keys = map.keySet();
        // 遍历键集 得到 每一个键
        for (String key : keys) {
          	//key  就是键
            //获取对应值
            String value = map.get(key);
            System.out.println(key+"的CP是:"+value);
        }  
    }
}

Traversal diagram:

1.5 entry key value pair object

We already know that there are two kinds of objects stored in the map, one is called key and the other is called value. They are one-to-one correspondence in the map. This pair of objects is also called an entry in the map. Entry encapsulates the correspondence of key value pairs into objects. That is, the key value pair object, so that when we traverse the map collection, we can obtain the corresponding key and corresponding value from each key value pair (entry) object.

Since entry represents a pair of keys and values, it also provides methods to obtain corresponding keys and values:

Methods for obtaining all entry objects are also provided in the map collection:

1.6 map set traversal key value pair method

Key value pair method: obtain the keys and values in the key value pair (entry) object through each key value pair (entry) object in the collection.

Operation steps and diagrams:

public class MapDemo02 {
    public static void main(String[] args) {
        // 创建Map集合对象 
        HashMap<String,String>();
        // 添加元素到集合 
        map.put("胡歌","大张伟");

        // 获取 所有的 entry对象  entrySet
        Set<Entry<String,String>> entrySet = map.entrySet();

        // 遍历得到每一个entry对象
        for (Entry<String,String> entry : entrySet) {
           	// 解析 
            String key = entry.getKey();
            String value = entry.getValue();  
            System.out.println(key+"的CP是:"+value);
        }
    }
}

Traversal diagram:

1.7 HashMap stores user-defined type keys

Exercise: each student (name, age) has its own home address. Then, since there is a corresponding relationship, store the student object and home address in the map set. The student is the key and the home address is the value.

Prepare student class:

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name,int age) {
        this.name = name;
        this.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 boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name,student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name,age);
    }
}

Write test class:

public class HashMapTest {
    public static void main(String[] args) {
        //1,创建Hashmap集合对象。
        Map<Student,String>map = new HashMap<Student,String>();
        //2,添加元素。
        map.put(newStudent("lisi",28),"上海");
        map.put(newStudent("wangwu",22),"北京");
        map.put(newStudent("zhaoliu",24),"成都");
        map.put(newStudent("zhouqi",25),"广州");
        map.put(newStudent("wangwu","南京");
        
        //3,取出元素。键找值方式
        Set<Student>keySet = map.keySet();
        for(Student key: keySet){
            Stringvalue = map.get(key);
            System.out.println(key.toString()+"....."+value);
        }
    }
}

1.8 LinkedHashMap

We know that HashMap ensures that the paired elements are unique and the query speed is fast, but the paired elements are stored in no order. What should we do to ensure order and speed?

Under HashMap, there is a subclass LinkedHashMap, which is a data storage structure composed of linked list and hash table.

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        LinkedHashMap<String,String> map = new LinkedHashMap<String,String>();
        map.put("邓超","孙俪");
        map.put("李晨","范冰冰");
        map.put("刘德华","朱丽倩");
        Set<Entry<String,String>> entrySet = map.entrySet();
        for (Entry<String,String> entry : entrySet) {
            System.out.println(entry.getKey() + "  " + entry.getValue());
        }
    }
}

result:

邓超  孙俪
李晨  范冰冰
刘德华  朱丽倩

1.9 map set exercise

Requirements:

Calculates the number of occurrences of each character in a string.

analysis:

code:

public class MapTest {
public static void main(String[] args) {
        //友情提示
        System.out.println("请录入一个字符串:");
        String line = new Scanner(system.in).nextLine();
        // 定义 每个字符出现次数的方法
        findChar(line);
    }
    private static void findChar(String line) {
        //1:创建一个集合 存储  字符 以及其出现的次数
        HashMap<Character,Integer> map = new HashMap<Character,Integer>();
        //2:遍历字符串
        for (int i = 0; i < line.length(); i++) {
            char c = line.charAt(i);
            //判断 该字符 是否在键集中
            if (!map.containsKey(c)) {//说明这个字符没有出现过
                //那就是第一次
                map.put(c,1);
            } else {
                //先获取之前的次数
                Integer count = map.get(c);
                //count++;
                //再次存入  更新
                map.put(c,++count);
            }
        }
        System.out.println(map);
    }
}

Chapter II detailed explanation of HashMap

2.1 what is a hash table

Hash table (also known as hash table) is a data structure that is accessed directly according to the key value. That is, it accesses records by mapping key values to a location in the table to speed up the search. This mapping function is called a hash function, and the array of records is called a hash table.

Given table m, there is a function f (key). For any given keyword value key, after substituting into the function, if the address recorded in the table containing the keyword can be obtained, table m is called hash table, and function f (key) is hash function.

For example, if we want to add or find an element, we can complete the operation by mapping the keyword of the current element to a position in the array through a function and locating it once through the array subscript.

The insertion process is as follows:

In the same way, the search operation first calculates the actual storage address through the hash function, and then takes it out from the corresponding address in the array.

Hash Collisions

However, nothing is perfect. What if two different elements have the same actual storage address obtained by the hash function? In other words, when we hash an element, get a storage address, and then insert it, we find that it has been occupied by other elements. In fact, this is the so-called hash collision, also known as hash collision. As we mentioned earlier, the design of hash function is very important. A good hash function will ensure simple calculation and uniform hash address distribution as much as possible. However, we need to be clear that the array is a continuous memory space of fixed length. No matter how good the hash function is, it can not guarantee that the obtained storage address will never conflict. So how to resolve hash conflicts? There are many solutions to hash conflicts: open addressing method (in case of conflict, continue to find the next unoccupied storage address), hash function method and chain address method. HashMap adopts the chain address method, that is, array + linked list.

2.2 implementation principle of HashMap

The backbone of HashMap is an entry array. Entry is the basic unit of HashMap. Each entry contains a key value pair. (in fact, the so-called map is actually a collection that saves the mapping relationship between two objects)

//HashMap的主干数组,可以看到就是一个Entry数组,初始值为空数组{},主干数组的长度一定是2的次幂。
//至于为什么这么做,后面会有详细分析。
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;

Entry is a static inner class in HashMap. The code is as follows

    static class Entry<K,V> implements Map.Entry<K,V> {
    	final K key;
    	V value;
    	Entry<K,V> next;//存储指向下一个Entry的引用,单链表结构
    	int hash;//对key的hashcode值进行hash运算后得到的值,存储在Entry,避免重复计算

    	/**
     	* Creates new entry.
     	*/
    	Entry(int h,K k,V v,Entry<K,V> n) {
        	value = v;
        	next = n;
        	key = k;
        	hash = h;
    } 

Therefore, the overall structure of HashMap is as follows:

In short, HashMap is composed of array + linked list. Array is the main body of HashMap, and linked list mainly exists to solve hash conflicts, If the location of the located array does not contain a linked list (the next of the current entry points to null), the operations such as finding and adding are fast and only need to be addressed once; if the location of the array contains a linked list, the time complexity of the addition operation is O (n). First traverse the linked list and overwrite it if it exists, otherwise add it; For the search operation, you still need to traverse the linked list, and then compare and search one by one through the equals method of the key object. Therefore, in terms of performance, the fewer linked lists in HashMap appear, the better the performance will be.

Several other important fields:

/**实际存储的key-value键值对的个数*/
transient int size;

/**阈值,当table == {}时,该值为初始容量(初始容量默认为16);当table被填充了,也就是为table分配内存空间后,
threshold一般为 capacity*loadFactory。HashMap在进行扩容时需要参考threshold,后面会详细谈到*/
int threshold;

/**负载因子,代表了table的填充度有多少,默认是0.75
加载因子存在的原因,还是因为减缓哈希冲突,如果初始桶为16,等到满16个元素才扩容,某些桶里可能就有不止一个元素了。
所以加载因子默认为0.75,也就是说大小为16的HashMap,到了第13个元素,就会扩容成32。
*/
final float loadFactor;

/**HashMap被改变的次数,由于HashMap非线程安全,在对HashMap进行迭代时,
如果期间其他线程的参与导致HashMap的结构发生变化了(比如put,remove等操作),
需要抛出异常ConcurrentModificationException*/
transient int modCount;

HashMap has four constructors. Other constructors will use the default values if the user does not pass in the initialCapacity and LoadFactor parameters.

InitialCapacity defaults to 16 and loadfactory defaults to 0.75

Let's look at one of them

From the above code, we can see that in the conventional constructor, memory space is not allocated for the array table (except for the constructor with a parameter specifying map), but the table array is really constructed when the put operation is executed

OK, let's take a look at the implementation of the put operation

public V put(K key,V value) {
    //如果table数组为空数组{},进行数组填充(为table分配实际内存空间),入参为threshold,
    //此时threshold为initialCapacity 默认是1<<4(24=16)
    if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }
   //如果key为null,存储位置为table[0]或table[0]的冲突链上
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);//对key的hashcode进一步计算,确保散列均匀
    int i = indexFor(hash,table.length);//获取在table中的实际位置
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
    //如果该对应数据已存在,执行覆盖操作。用新value替换旧value,并返回旧value
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    modCount++;//保证并发访问时,若HashMap内部结构发生变化,快速响应失败
    addEntry(hash,key,value,i);//新增一个entry
    return null;
}

The inflatetable method is used to allocate storage space in memory for the backbone array table. Through rounduptopowerof2 (tosize), you can ensure that the capacity is greater than or equal to the nearest quadratic power of tosize. For example, tosize = 13, then capacity = 16; to_ size=16,capacity=16; to_ size=17,capacity=32。

private void inflateTable(int toSize) {
    int capacity = roundUpToPowerOf2(toSize);//capacity一定是2的次幂
    /**此处为threshold赋值,取capacity*loadFactor和MAXIMUM_CAPACITY+1的最小值,
    capaticy一定不会超过MAXIMUM_CAPACITY,除非loadFactor大于1 */
    threshold = (int) Math.min(capacity * loadFactor,MAXIMUM_CAPACITY + 1);
    table = new Entry[capacity];
    initHashSeedAsNeeded(capacity);
}

This processing in rounduptopowerof2 ensures that the array length must be a power of 2, integer Highestonebit is used to obtain the value represented by the leftmost bit (other bits are 0).

 private static int roundUpToPowerOf2(int number) {
    // assert number >= 0 : "number must be non-negative";
    return number >= MAXIMUM_CAPACITY
            ? MAXIMUM_CAPACITY
            : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
}

hash function

/**这是一个神奇的函数,用了很多的异或,移位等运算
对key的hashcode进一步进行计算以及二进制位的调整等来保证最终获取的存储位置尽量分布均匀*/
final int hash(Object k) {
    int h = hashSeed;
    if (0 != h && k instanceof String) {
        return sun.misc.Hashing.stringHash32((String) k);
    }

    h ^= k.hashCode();

    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

The value calculated by the hash function above is further processed by indexfor to obtain the actual storage location.

/**
 * 返回数组下标
 */
static int indexFor(int h,int length) {
    return h & (length-1);
}

H & (length-1) ensure that the obtained index must be within the array range. For example, the default capacity is 16, length-1 = 15, H = 18, which is converted into binary and calculated as index = 2. Bit operation has higher performance for computers (there are a lot of bit operations in HashMap)

Therefore, the final storage location determination process is as follows:

Let's look at the implementation of addentry:

void addEntry(int hash,K key,V value,int bucketIndex) {
    if ((size >= threshold) && (null != table[bucketIndex])) {
        resize(2 * table.length);//当size超过临界阈值threshold,并且即将发生哈希冲突时进行扩容
        hash = (null != key) ? hash(key) : 0;
        bucketIndex = indexFor(hash,table.length);
    }

    createEntry(hash,bucketIndex);
}

From the above code, we can know that when a hash conflict occurs and the size is greater than the threshold, the array needs to be expanded. During capacity expansion, we need to create a new array with a length of twice the previous array, and then transfer all the elements in the current entry array. The length of the new array after capacity expansion is twice the previous one, so capacity expansion is a relatively resource consuming operation.

2.3 why must the array length of HashMap be a power of 2?

Let's continue with the resize method mentioned above

void resize(int newCapacity) {
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    if (oldCapacity == MAXIMUM_CAPACITY) {
        threshold = Integer.MAX_VALUE;
        return;
    }

    Entry[] newTable = new Entry[newCapacity];
    transfer(newTable,initHashSeedAsNeeded(newCapacity));
    table = newTable;
    threshold = (int)Math.min(newCapacity * loadFactor,MAXIMUM_CAPACITY + 1);
}

If the array is expanded, the length of the array changes, and the storage location index = h& (length-1), the index may also change. You need to recalculate the index. Let's take a look at the transfer method first

void transfer(Entry[] newTable,boolean rehash) {
    int newCapacity = newTable.length;
	//for循环中的代码,逐个遍历链表,重新计算索引位置,将老数组数据复制到新数组中去(数组不存储实际数据,所以仅仅是拷贝引用而已)
    for (Entry<K,V> e : table) {
        while(null != e) {
            Entry<K,V> next = e.next;
            if (rehash) {
                e.hash = null == e.key ? 0 : hash(e.key);
            }
            int i = indexFor(e.hash,newCapacity);
            //将当前entry的next链指向新的索引位置,newTable[i]有可能为空,有可能也是个entry链,如果是entry链,直接在链表头部插入。
            e.next = newTable[i];
            newTable[i] = e;
            e = next;
        }
    }
}

This method traverses the data in the old array one by one and throws it into the new expanded array. Our array index position is calculated by hashing the hashcode of the key value, and then performing bit operation with length-1 to obtain the final array index position.

The array length of HashMap must maintain the power of 2. For example, if the binary representation of 16 is 10000, then the length-1 is 15 and the binary representation is 01111. Similarly, the array length after capacity expansion is 32, the binary representation is 100000, the length-1 is 31 and the binary representation is 01111. We can also see from the figure below that this will ensure that all the low bits are 1, and there is only one bit difference after capacity expansion, that is, the leftmost 1 is added. In this way, when passing through H & (length-1), as long as the leftmost difference corresponding to h is 0, It can ensure that the new array index is consistent with the old array index (greatly reducing the data position re exchange of the old array that has been hashed well before).

In addition, keeping the array length to the power of 2 and the low order of length-1 to 1 will make the obtained array index more uniform

We see that the & operation above, The high level will not affect the results (the hash function uses various bit operations to make the low bit more hash). We only focus on the low bit. If all the low bits are 1, the change of any bit will affect the result for the low part of H, that is, to get the storage location of index = 21, there is only one combination of the low bits of h. This is also the reason that the array length must be 2 Power.

If it is not the power of 2, that is, the low order is not all 1. At this time, to make the low order part of index = 21 and h no longer unique, the probability of hash conflict will become greater. At the same time, the bit corresponding to index will not be equal to 1 anyway, and the corresponding array positions will be wasted.

Get method

 public V get(Object key) {
	//如果key为null,则直接去table[0]处去检索即可。
    if (key == null)
        return getForNullKey();
    Entry<K,V> entry = getEntry(key);
    return null == entry ? null : entry.getValue();
}

The get method returns the corresponding value through the key value. If the key is null, go directly to table [0] for retrieval. Let's take another look at the getentry method

final Entry<K,V> getEntry(Object key) {
        
    if (size == 0) {
        return null;
    }
    //通过key的hashcode值计算hash值
    int hash = (key == null) ? 0 : hash(key);
    //indexFor (hash&length-1) 获取最终数组索引,然后遍历链表,通过equals方法比对找出对应记录
    for (Entry<K,V> e = table[indexFor(hash,table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash && 
            ((k = e.key) == key || (key != null && key.equals(k))))
            return e;
    }
    return null;
}    

It can be seen that the implementation of the get method is relatively simple. Key (hashcode) – > hash – > indexfor – > the final index position, find the corresponding position table [i], check whether there is a linked list, traverse the linked list, and compare and find the corresponding records through the equals method of key. It should be noted that some people think that it is unnecessary to judge e.hash = = hash after locating the array position and then traversing the linked list. It can only be judged by equals. In fact, it is not. Imagine that if the passed in key object rewrites the equals method but does not rewrite the hashcode, and the object happens to be located in the array position. If only equals is used to judge, it may be equal, but its hashcode is inconsistent with the current object. In this case, according to the hashcode convention of the object, the current object cannot be returned, but null should be returned, The following examples will further explain.

2.4 rewriting the equals method requires rewriting the hashcode method at the same time

Finally, let's talk about an old problem. It is mentioned in various materials that "when rewriting equals, you should also overwrite hashcode". Let's take a small example to see what happens if equals is rewritten without rewriting hashcode

public class MyTest {
	private static class Person{
    	int idCard;
    	String name;

    	public Person(int idCard,String name) {
        	this.idCard = idCard;
        	this.name = name;
    	}
    	@Override
    	public boolean equals(Object o) {
        	if (this == o) {
            	return true;
        	}
        	if (o == null || getClass() != o.getClass()){
            	return false;
        	}
        	Person person = (Person) o;
        	//两个对象是否等值,通过idCard来确定
        	return this.idCard == person.idCard;
    	}

	}
	public static void main(String []args){
    	HashMap<Person,String> map = new HashMap<Person,String>();
    	Person person = new Person(1234,"乔峰");
    	//put到hashmap中去
    	map.put(person,"天龙八部");
    	//get取出,从逻辑上讲应该能输出“天龙八部”
    	System.out.println("结果:"+map.get(new Person(1234,"萧峰")));
	}
}


实际输出结果:null

If we have a certain understanding of the principle of HashMap, this result is not difficult to understand. Although the keys used in the get and put operations are logically equivalent (they are equivalent through equals comparison), since the hashcode method is not rewritten, the key (hashcode1) – > hash – > indexfor – > final index position during the put operation, and the key (hashcode1) – > hash – > indexfor – > final index position when the value is retrieved through the key, Because hashcode1 is not equal to hashcode2, it does not locate an array position and returns a logically wrong value null (it may also happen to locate an array position, but it will also judge whether the hash value of its entry is equal, as mentioned in the get method above.)

Therefore, when rewriting the equals method, you must pay attention to rewriting the hashcode method. At the same time, you must ensure that two objects that are equal are judged by equals, and calling the hashcode method will return the same integer value. If equals judges that two objects are not equal, their hashcodes can be the same (but hash conflicts will occur, which should be avoided as far as possible).

2.5 JDK1. Performance optimization of HashMap in 8

If there is too much data on the chain of an array slot (that is, if the zipper is too long), what should we do to reduce the performance? JDK1.8 optimizes the red black tree on the basis of jdk1.7. That is, when the linked list exceeds 8, the linked list will be transformed into a red black tree. The characteristics of red black tree rapid addition, deletion and query will be used to improve the performance of HashMap, in which the insertion, deletion, search and other algorithms of red black tree will be used.

Chapter III simulated landlords reshuffle and deal

3.1 case introduction

Complete the shuffle and deal according to the rules of fighting the landlord.

Specific rules:

3.2 case demand analysis

Complete the mapping relationship between numbers and cards:

Use the two column map (HashMap) set to complete the corresponding relationship between a number and string Solitaire (equivalent to a dictionary).

Shuffle and deal through numbers

Design everyone and their cards as ArrayList, store the last three cards directly in the cards, and deal the remaining cards in turn by taking a mold of 3.

In the process of storage, the number size is required to correspond to the size of the landlord rule.

Assign numbers representing different cards to different players and cards.

Find the corresponding character display through the map set.

By querying the corresponding relationship between cards and numbers, the numbers are converted into card strings for display.

3.3 implementation code steps

public class Poker {
    public static void main(String[] args) {
        /*
         * 1组装54张扑克牌
         */
        // 1.1 创建Map集合存储
        HashMap<Integer,String> pokerMap = new HashMap<Integer,String>();
        // 1.2 创建 花色集合 与 数字集合
        ArrayList<String> colors = new ArrayList<String>();
        ArrayList<String> numbers = new ArrayList<String>();

        // 1.3 存储 花色 与数字
        Collections.addAll(colors,"♦","♣","♥","♠");
        Collections.addAll(numbers,"2","A","K","Q","J","10","9","8","7","6","5","4","3");
        // 设置 存储编号变量
        int count = 1;
        pokerMap.put(count++,"大王");
        pokerMap.put(count++,"小王");
        // 1.4 创建牌 存储到map集合中
        for (String number : numbers) {
            for (String color : colors) {
                String card = color + number;
                pokerMap.put(count++,card);
            }
        }
        /*
         * 2 将54张牌顺序打乱
         */
        // 取出编号 集合
        Set<Integer> numberSet = pokerMap.keySet();
        // 因为要将编号打乱顺序 所以 应该先进行转换到 list集合中
        ArrayList<Integer> numberList = new ArrayList<Integer>();
        numberList.addAll(numberSet);

        // 打乱顺序
        Collections.shuffle(numberList);

        // 3 完成三个玩家交替摸牌,每人17张牌,最后三张留作底牌
        // 3.1 发牌的编号
        // 创建三个玩家编号集合 和一个 底牌编号集合
        ArrayList<Integer> noP1 = new ArrayList<Integer>();
        ArrayList<Integer> noP2 = new ArrayList<Integer>();
        ArrayList<Integer> noP3 = new ArrayList<Integer>();
        ArrayList<Integer> dipaiNo = new ArrayList<Integer>();

        // 3.2发牌的编号
        for (int i = 0; i < numberList.size(); i++) {
            // 获取该编号
            Integer no = numberList.get(i);
            // 发牌
            // 留出底牌
            if (i >= 51) {
                dipaiNo.add(no);
            } else {
                if (i % 3 == 0) {
                    noP1.add(no);
                } else if (i % 3 == 1) {
                    noP2.add(no);
                } else {
                    noP3.add(no);
                }
            }
        }

        // 4 查看三人各自手中的牌(按照牌的大小排序)、底牌
        // 4.1 对手中编号进行排序
        Collections.sort(noP1);
        Collections.sort(noP2);
        Collections.sort(noP3);
        Collections.sort(dipaiNo);

        // 4.2 进行牌面的转换
        // 创建三个玩家牌面集合 以及底牌牌面集合
        ArrayList<String> player1 = new ArrayList<String>();
        ArrayList<String> player2 = new ArrayList<String>();
        ArrayList<String> player3 = new ArrayList<String>();
        ArrayList<String> dipai = new ArrayList<String>();

        // 4.3转换
        for (Integer i : noP1) {
            // 4.4 根据编号找到 牌面 pokerMap
            String card = pokerMap.get(i);
            // 添加到对应的 牌面集合中
            player1.add(card);
        }

        for (Integer i : noP2) {
            String card = pokerMap.get(i);
            player2.add(card);
        }
        for (Integer i : noP3) {
            String card = pokerMap.get(i);
            player3.add(card);
        }
        for (Integer i : dipaiNo) {
            String card = pokerMap.get(i);
            dipai.add(card);
        }

        //4.5 查看
        System.out.println("令狐冲:"+player1);
        System.out.println("石破天:"+player2);
        System.out.println("鸠摩智:"+player3);
        System.out.println("底牌:"+dipai);
    }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>