解决方案 »

  1.   

    https://blog.csdn.net/qq_24251323/article/details/52748398 参考博文
      

  2.   

    Integer的hashCode就是数字本身,HashSet其实用的是HashMap的实现,下标是根据hashCode算出来的
    (h = key.hashCode()) ^ (h >>> 16),低于2的16次方的数字hash的结果还是自身,你的测试只能说明你的数字太小
      

  3.   


    import java.util.HashSet;
    public class HashTableTest {
        public static void main(String[] args) {
            HashSet<Integer> set = new HashSet<Integer>();
            for (int i = 1; i < 12; i++) {
                set.add(i);
            }
            set.add(17);
            System.out.println(set);
            System.out.println(hash(17));
        }
    /*
    set.add()方法其实在底层最终是调用了一个hash方法,此方法是对数据的hashcode进行处理,然后返回一个整数,这个数最终就是在set集合中存储的位置
    */
        static final int hash(Object key) { //此方法对数据的hashcode进行处理
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }
    }
    运行结果为:
    [1, 17, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    17
    通过上面的代码可以看出,set 的存储确实是无序的,那么为什么楼主的30个数字全都是有序输出呢,我们可以根据set的存储原理来分析一下。
    首先要知道Hash表是由数组和链表来进行数据存储的,默认情况下数组长度是16(这个长度是动态变化的),当里面的数据超过阈值的时候(当前数组的0.75倍),数组就会自动的增加或减少(增加或减少的数值为2的倍数)import java.util.HashSet;
    public class HashTableTest {
        public static void main(String[] args) {
    //        HashSet<Integer> set = new HashSet<Integer>();
    //        for (int i = 0; i < 11; i++) {
    //            set.add(i);
    //        }
    //        set.add(17);
    //        System.out.println(set);
    //        System.out.println(hash(17));
            for(int i = 1; i<12;i++){
                System.out.print(hash(i) + ",");
            }
            System.out.print(hash(17));
        }    static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }
    }运行结果为:
    1,2,3,4,5,6,7,8,9,10,11,12,17
    首先我先输出一下这12个数字经过hash方法处理过的结果,这就是每个数字所对应的最终在内部存储的位置,首先添加第一个数据1,那么这个数字和hash方法处理过返回的数字相同,那么底层就用这个1%16(数组默认为16)得到的余数为1,那么就会将1存进索引为1的数组中,,同理类推2就会存入索引为2的数组中,那么到了17的时候得到的余数为1,就会存入到索引为1的数组中。如图1所示:那么当我们继续往里面添加一个数字12的时候(代码在下面),经过hash方法的计算,整数12的这个返回值也是12,(其实10000以前的数值包括后面的一些整数返回来的值都是本身,当你查询99999的时候返回值就不是本身了)那么我们前面说过当数据超过阈值的时候(默认值16*0.75 = 12)数组就会增加2的倍数变为32,此时数据在集合内部的存入位置就会发生改变。如下图2所示:那么当set遍历的时候就会从索引1的位置开始遍历一直到最后的17结束,这里的17是因为数组的长度发生了变化,从16变为32,所以17%32的余数为17,位置就发生了变化
    import java.util.HashSet;
    public class HashTableTest {
        public static void main(String[] args) {
            HashSet<Integer> set = new HashSet<Integer>();
            for (int i = 1; i < 13; i++) {
                set.add(i);
            }
            set.add(17);
            System.out.println(set);
            System.out.println(hash(17));
    //        for(int i = 1; i<13;i++){
    //            System.out.print(hash(i) + ",");
    //        }
    //        System.out.print(hash(17));    }    static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }
    }运行结果为:
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 17]
    17
    此时数组长度为32,32*0.75=24,也就是说当我们从1添加到24的时候,他的输出顺序都是有序的运行结果:
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]当你在往里面继续添加数字25的时候数组的长度又超过阈值,此时数组长度会自动变为128,128*0.75=96‬那么这时候你往里面存入1-96的时候输出是都是按照顺序输出的。可自行测试。
      

  4.   

    你使用的是int类型,本身哈希值就是数值,然后结果就是有序的
      

  5.   

    无序指的是你遍历时不保证输出的顺序=输入的顺序
    换String输入试试看