如何从作为POJO的键获取映射的值

时间:2014-09-24 10:37:28

标签: map equals key-value hashcode pojo

我有以下功能

Map<MyClass, String> someFunction() {
    Map<MyClass, String> result = new HashMap<>();
    return result.put(new MyClass("someString"), "someOtherString"));
}

MyClass的实现如下所示:

public class MyClass{

    String string;

    public MyClass(String string) {
        this.string = string;
    }

    public void setString(String string) {
        this.string = string;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((string== null) ? 0 : string.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        MyClass other = (MyClass) obj;
        if (string== null) {
            if (other.string!= null) {
                return false;
            }
        } else if (!string.equals(other.string)) {
            return false;
        }
        return true;
    }

}

在我的测试中,我正在做以下事情:

@Test
public void test() {
    Map<MyClass, String> outcome = classUnderTest.someFunction();

    assertThat(outcome.get(new MyClass("someString")), is("someOtherString"));
}

但是这个测试失败了,因为实际是空的。 如果我尝试以下内容:

assertThat(outcome.keySet(), hasItem(MY_CLASS));

这也失败了,告诉我,这些是不同的实例。我甚至试图调试我的测试,但它永远不会达到equals方法。你能告诉我这里发生了什么吗?

2 个答案:

答案 0 :(得分:0)

在您的函数中,您将返回null

从JavaDoc for HashMap:

  

公共V放(K键,V值)

Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.

Specified by:
    put in interface Map<K,V>
Overrides:
    put in class AbstractMap<K,V>
Parameters:
    key - key with which the specified value is to be associated
    value - value to be associated with the specified key
Returns:
    the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)

put()返回过去的内容,而不是你刚放在那里的内容

答案 1 :(得分:0)

您确定,您的方法不会修改objecT吗?我认为,someFunction取代string中的MyClass。这导致您的MyClass对象返回另一个hashCode。

HashMap就是这样的:

放:

  • 计算密钥的hashCode。在该hashCode下存储值

得到:

  • 计算密钥的hashCode。使用该hashCode搜索值。如果有值,则可以调用equals

所以:永远不要使用可变值作为键!否则,您可能会丢失数据(或难以解决)

尝试执行此测试,它应该是绿色

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

public class SomeTest {

    Map<MyClass, String> someFunction() {
        Map<MyClass, String> result = new HashMap<>();
        result.put(new MyClass("someString"), "someOtherString");
        return result;
    }

    @Test
    public void test() {
        Map<MyClass, String> outcome = someFunction();

        assertThat(outcome.get(new MyClass("someString")), is("someOtherString"));
    }

    public static class MyClass {

        String string;

        public MyClass(String string) {
            this.string = string;
        }

        public void setString(String string) {
            this.string = string;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((string == null) ? 0 : string.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            MyClass other = (MyClass) obj;
            if (string == null) {
                if (other.string != null) {
                    return false;
                }
            } else if (!string.equals(other.string)) {
                return false;
            }
            return true;
        }

    }
}

但是如果你将MyClass对象添加到Map后进行修改,则测试会变为红色:

Map<MyClass, String> someFunction() {
    Map<MyClass, String> result = new HashMap<>();
    MyClass key = new MyClass("someOldString");
    result.put(key, "someOtherString");
    key.setString("someString");
    return result;
}