软件构造 Blog-3 Mutable Class与Set的一些事

软件构造 Blog-3 Mutable类与Set的一些事


今天上课的时候,Mr.Wang提到这么一点(意思类似但是具体的表述可能有所不同):有些mutable的对象,加入Set之后,如果改变其值,会出现找不到该值的情况。并且在下课后,用了一段代码更加仔细的表述了一下这个问题。(伪)代码如下:

  StringBuilder a = new StringBuilder("a");
  Set s = new HashSet();
  s.add(a); 
  System.out.println(s.contains(a)); ===>true
  a.append("b");
  System.out.println(s.contains(a));   ===>true
  List<String> list = new ArrayList<>();
  list.add("a");
  Set<List<String>> set = new HashSet<List<String>>();
  set.add(list);
  System.out.println(set.contains(list));  ==>true
  list.add("b");
  System.out.println(set.contains(list));  ==>false

在刚下课的时候其实就和室友讨论了一下这个问题,认为就是hashCode的问题,但是没有进行深入的实验,后来Mr.Wang的说法证实了我们的猜想。然而在给出的例子里使用的都是已经定义好的mutable的类型,不好直接说明情况,然后出于一种好奇,我又忙(bu)里(xie)偷(shi)闲(yan)的用代码说明一下,于是我先写了下面的代码:

public class testMutable {
    public static void main(String [] args){
        String label = "name";
        Set<TestClass> setInstance = new HashSet<>();
        TestClass testClass1 = new TestClass(label);
        //先加入mutable的对象
        setInstance.add(testClass1);
        System.out.println(setInstance.contains(testClass1));
        String something = "something";
        //更改mutable对象的field
        testClass1.add(something);
        System.out.println(setInstance.contains(testClass1));

    }
}

class TestClass{
    private final String label;
    public Set<String> set;
    //此处是一个mutable的类
    public TestClass(String label){
        this.label = label;
        set = new HashSet<>();
    }

    public String getLabel(){
        return this.label;
    }
    public void add(String something){
        set.add(something);
    }
}

测试的结果为

true
true

出现这个结果是跟StringBuilder的结果是一致的,但和Lisr的结果不一样。由于猜测是因为hashCode的问题,因此我重写了TestClass类的hashCode方法。
重写的方法如下:

    @Override
    public int hashCode(){
        int result = 17;
        result = result * 31 + label.hashCode();
        result = result * 31 + set.hashCode();
        return result;
    }

然后的测试结果就变成了

true
false

可以看到这样的结果就可以说明hashCode方法对于HashSet判断是否出现有着重要的关系。但是如果我不重写hashCode方法,而是重写equals方法会不会有相同的效果呢。
注释掉已写的hashCode方法,又写了下面的一个equals方法。

    @Override
    public boolean equals(Object obj) {
        if(obj == this)
            return true;
        if(obj instanceof TestClass) {
            TestClass testClass = (TestClass) obj;
            if(testClass.getLabel().equals(this.getLabel())) {
                if(testClass.set == this.set)
                    return true;
                if(testClass.set.size() != this.set.size())
                    return false;
                else {
                    return this.set.containsAll(testClass.set);
                }
            }
            return false;
        }
        return false;
    }

测试结果变成了

true
true

于是,我们可以说hashCode确实在HashSet的判断重复和是否存在有着很大的作用。但是,我又发现了下面一个问题(这表明不想让我写实验的事实)我将测试的主函数改成了下面的样子:

public class testMutable {
    public static void main(String [] args){
        String label = "name";
        Set<TestClass> setInstance = new HashSet<>();

        TestClass testClass1 = new TestClass(label);
        setInstance.add(testClass1);
        System.out.println("Contains testClass1: " + setInstance.contains(testClass1));

        String something = "something";
        testClass1.add(something);
        System.out.println("After add something: "+setInstance.contains(testClass1));
        System.out.println("set has " + setInstance.size());

        TestClass testClass2 = new TestClass(label);
        testClass2.set = testClass1.set;

        System.out.println("Add testClass2: " + setInstance.add(testClass2));
        System.out.println("Contains testClass2: " + setInstance.contains(testClass2));

        System.out.println("set has " + setInstance.size());

    }
}

测试的结果就变成了

Contains testClass1: true
After add something: false
set has 1
Add testClass2: true
Contains testClass2: true
set has 2

在最开始的时候,我以为是一个错误。其实是因为我在增加testClass1的时候由于已经更改过所以导致testClass1的hashCode就改变了。这样我在第二次加入一个相同的哈希值的testClass2的时候,才可以加进去。
其实HashSet的底部是一个HashMap来具体实现的,所以我们很多对于集合的理解都可以借用HashMap的理解。在判断是不是相等的时候,其实先使用的是判HashCode是不是相同的然后再使用equals的方法来进行。
更多详细的介绍,希望大家去Java Set集合的详解看一下,确实感觉看完之后会明白更多。


后记

这篇blog本来是周三开始写的,准备当晚就写完的,结果一直匆匆忙忙的拖到周六才写的差不多,而且也很水。感觉自己应该提高一下效率了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值