java - Set.equals 的奇怪行为

标签 java hibernate set equals hashcode

我在尝试查看两个集合是否相等时遇到了一个奇怪的行为。我已经覆盖了 equals 和哈希码:

public class Metric {


    private String id;

    private Sensor sensor;

    private String metricName;

    private String metricDescription;

    //getters, setters, toString()...

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + ((metricDescription == null) ? 0 : metricDescription.hashCode());
        result = prime * result + ((metricName == null) ? 0 : metricName.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;
        Metric other = (Metric) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (metricDescription == null) {
            if (other.metricDescription != null)
                return false;
        } else if (!metricDescription.equals(other.metricDescription))
            return false;
        if (metricName == null) {
            if (other.metricName != null)
                return false;
        } else if (!metricName.equals(other.metricName))
            return false;
        return true;
    }

}

我有意将传感器信息排除在 hashCode 和 equals 之外,但在两者中应该没有区别。

现在,考虑以下代码:

SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session session = sessionFactory.getCurrentSession();
    Transaction tx = null;

    try {
        tx = session.beginTransaction();
        session.save(datasource);
        session.save(sensorType);
        session.save(sensor);
        session.save(metric1);
        session.save(metric2);
        session.getTransaction().commit();
    } catch (HibernateException e) {
        if (tx != null)
            tx.rollback();
        throw e;
    } finally {
        if (session.isOpen())
            session.close();
    }

    try {
        session = sessionFactory.getCurrentSession();
        tx = session.beginTransaction();
        sameSensor = (Sensor) session.get(Sensor.class, new String(sensor.getId()));
    } catch (HibernateException e) {
        if (tx != null)
            tx.rollback();
        throw e;
    } finally {
        if (session.isOpen())
            session.close();
    }

    // simply retrieve the metrics
    Set<Metric> sensorMetrics = sensor.getMetrics();
    Set<Metric> sameSensorMetrics = sameSensor.getMetrics();
    System.out.println("SENSOR METRIC");
    for(Metric m : sensorMetrics) {
        System.out.println(m.getMetricName() + ":" + m.hashCode());
        System.out.println(sameSensorMetrics.contains(m));
    }
    System.out.println("SAME SENSOR METRIC");
    for(Metric m : sameSensorMetrics) {
        System.out.println(m.getMetricName() + ":" + m.hashCode());
        System.out.println(sensorMetrics.contains(m));

    }

这两个集合应该是相同的(并且所有的 hascode 都是),但我得到以下结果:

SENSOR METRIC
metric2name_addSensor_1393695505000:-1437647480
true
metric1name_addSensor_1393695505000:2040143911
true

SAME SENSOR METRIC
metric1name_addSensor_1393695505000:2040143911
false
metric2name_addSensor_1393695505000:-1437647480
false

即使指标相同(我已经检查了所有对的相等性,结果是正确的)指标包含在一组而不是另一组中......我真的无法解释这一点并且会很感激任何帮助。

我已经给出了我认为很重要的代码片段,如果需要更多信息,我将非常乐意提供。谢谢。

编辑:

1)根据dfb请求初始化传感器的代码:

/*
 * Create all the sensor-related information to insert
 */

DataSource datasource = new DataSource();
datasource.setDatasourceName(
        createUniqueString("datasource","addSensor"));
datasource.setDatasourceDescription(
        createUniqueString("datasource","addSensor","description"));

SensorType sensorType = new SensorType();
sensorType.setSensorTypeName(
        createUniqueString("sensortype","addSensor"));
sensorType.setSensorTypeDescription(
        createUniqueString("sensortype","addSensor","description")); 

Sensor sensor = new Sensor();
sensor.setDatasource(datasource);
sensor.setSensorType(sensorType);
sensor.setSensorName(createUniqueString("sensorname","addSensor"));
sensor.setSensorDescription(createUniqueString("sensordesc","addSensor","description"));

Metric metric1 = new Metric();
metric1.setMetricDescription(
        createUniqueString("metric1name","addSensor","description"));
metric1.setMetricName(
        createUniqueString("metric1name","addSensor"));
metric1.setSensor(sensor);

Metric metric2 = new Metric();
metric2.setMetricDescription(
        createUniqueString("metric2name","addSensor","description"));
metric2.setMetricName(
        createUniqueString("metric2name","addSensor"));
metric2.setSensor(sensor);

sensor.addMetric(metric1);
sensor.addMetric(metric2);

和传感器构造函数:

Sensor() {
    this.metrics = new HashSet<Metric>();
}

2) 奇怪的行为似乎是保存的传感器实例,而不是加载的实例:

Set<Metric> sensorMetrics2 = sensor.getMetrics();
Set<Metric> sensorMetrics = sensor.getMetrics();
System.out.println(sensorMetrics2.equals(sensorMetrics));
System.out.println(sensorMetrics.equals(sensorMetrics));

Set<Metric> sameSensorMetrics2 = sameSensor.getMetrics();
Set<Metric> sameSensorMetrics = sameSensor.getMetrics();
System.out.println(sameSensorMetrics2.equals(sameSensorMetrics));
System.out.println(sameSensorMetrics.equals(sameSensorMetrics2));

结果:

false
false

true
true

最佳答案

以下构造对于 Hibernate 来说是有问题的,因为 Hibernate 由于需要延迟加载而倾向于为实体创建代理:

if (getClass() != obj.getClass())
  return false;

Proxy 是 Metrics 的子类,这就是为什么上面的代码不起作用,但代码可能起作用:

if (!(obj instanceof Metrics)) {
  return false;
}

有关覆盖实体的 equals 和 hashcode 的更多说明,请参见 Hibernate documentation . instanceof 也可以带来惊喜,如 this 中所述博文。

关于java - Set.equals 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22118114/

相关文章:

c - 如何修复有关 Mandelbrot 集的 Pthreads 代码?

c# - c# 中 Get 和 Set 方法的目的是什么?

java - 如何在具有即时消息功能的应用程序中保持黑莓套接字连接

c# - 公交公交算法

java - 使用 XSAttributeUse.getValueConstraintValue() 时,Apache Xerces 抛出 java.lang.NoSuchMethodError

java - jUnit + jMock 和 log4j

java - 无法将消息发送到远程对等本地类不兼容 : stream classdesc serialVersionUID

hibernate - 在 hibernate/jpa 环境中实际删除实体?

python - 生成具有多个列的.CSV-使用字典吗?

Hibernate 注释 - 不区分大小写的 UniqueConstraint