《Thinking in Java》第二版P346—关于HashMap的思考

今天学习Java入门之作《Thinking in Java》,看的非常过瘾。在看到第七章关于HashMap的实现案例中,有一点自己的思考。

一个小功能

作者在举例如何运用HashMap时,编写了一个查看随机数是否均匀排布的功能,具体实现是:

  1. 设置循环次数为10000,利用(int)Math.random()*20生成0-19范围内的10000个随机数

  2. 利用该随机数作为HashMap的key值,存入HashMap中,利用containsKey(k)函数判断,若已存在该key,则value+1;若不存在,则新建一个节点,设置value初始值为1

  3. 遍历打印该HashMap对象,查看均匀排布情况

总的来说功能不是很复杂,利用key的唯一性来确保新生成的随机数总是能被统计到,利用value值来统计生成的随机数个数。

书中源码如下:

public static class Counter{
    public Counter(){};
        int i = 1;
        public String toString(){
            return Integer.toString(i);
        }
    }
    public static void main(String[] args) {
        HashMap<Integer,Counter> hm = new HashMap<>();
        for(int i = 0;i < 10000;i++){
            Integer k = (int)(Math.random()*20);
            if(hm.containsKey(k)){
              hm.get(k).i++;
            }else{
                hm.put(k, new Counter());
            }
        }
        System.out.println(hm);
    }

作者提出的问题

这里作者回答了为什么要新建Counter类来进行value存储的问题:
(详见原著P346)

    你可能会猜想class Counter的必要性,看起来它似乎连外覆盖类Integer的功能都不具备。为什么不使用int或Integer呢?你不能使用int,因为所有容器都只能持有Object的reference。
    ……
    不过,使用Java外覆盖类时,你只能在初始化时设定其值。换句话说你不能在喊声外覆盖类对象后改变其值。因此我们需要撰写新的class来满足我们的需求

简单点来说,就是1、不能直接用int作为value的类型,因为HashMap的

我的思路

我也尝试了一下,如果直接写成
hm.get(k)++;
是不行的,会报invalid argument to operation ++/–,即该类型不支持直接的++/–操作。

有没有办法解决呢?其实是有的,我的方法利用了HashMap不允许重复key值的特点,换句话说就是,如果HashMap收到了重复的key值,会用新的value将原来的value覆盖

代码实现如下:

public static void main(String[] args) {
        HashMap<Integer,Integer> hm = new HashMap<>();
        for(int i = 0;i < 10000;i++){
            Integer k = (int)(Math.random()*20);
            if(hm.containsKey(k)){
                hm.put(k, (hm.get(k)+1));
            }else{
                hm.put(k, new Integer(1));
            }
        }
        System.out.println(hm);
}

这里使用了覆盖的方法,不必新建类也能实现key值的替换。代码运行结果如下图:

        {0=527, 1=520, 2=495, 3=475, 4=476, 5=499, 6=501, 7=510, 8=489, 9=544, 10=520, 11=511, 12=481, 13=481, 14=501, 15=490, 16=489, 17=472, 18=507, 19=512}

与原著中期望结果一致(随机数次数每次均不同,会有差异)

总结

我的这种方法比较讨巧,写起来会容易一些,是一种面向过程的编程思路。但如果数据过大,我觉得在效率上不如原著。

于是我做了进一步的测试

将随机数改为10000000(1千万)后,测试100次运行平均时间(ms),结果如下:

    原著方法 平均值:
    404
    我的方法 平均值:
    561

我觉得原因如下:
我的方法由于每次需要提取value,做出修改后又填入,效率上会低不少。

而原著的方法则是直接对对象的变量进行++运算操作,更加容易理解,实现起来难度较小。

综上,其实我更认同原著的方法,在面向对象的编程领域,就应该用面向对象的思想来解决问题。我的方法是为了实现而去实现,只能说提供了一种解决该问题的新的思路和尝试。虽然问题很简单,但我仍想记下来,留给以后的自己看一看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值