查找集合中的对象是否具有相同的字段值

时间:2018-05-16 17:07:40

标签: java collections equals jtree

我正在尝试创建一个编辑器来编辑在JTree中选择的多个设备。

如果Collection中的项目对于某个字段都具有相同的值,我将在编辑器表单中显示该值。如果它们具有不同的值,我将显示“多个值”

我试图利用这样的东西,但仅限于比较两个项目。我想为集合中的所有项目执行此操作。

 private static List<String> difference(Student s1, Student s2) {
 List<String> values = new ArrayList<>();
 for (Field field : s1.getClass().getDeclaredFields()) {
    // You might want to set modifier to public first (if it is not public yet)
    field.setAccessible(true);
    Object value1 = field.get(s1);
    Object value2 = field.get(s2); 
    if (value != null && value != null) {
        System.out.println(field.getName() + "=" + value1);
        System.out.println(field.getName() + "=" + value2);
        if (!Objects.equals(value1, value2) {
            values.add(value2);
        }
    }
}
return values;

}

有人可以举例说明如何确定集合中对象具有相同值的字段吗?

我的哈希和等于代码如下。我假设这可以使用内置的Collection方法完成,但我很欣赏一个例子。

    @Override
public int hashCode() {
    int hash = 5;
    hash = 47 * hash + (this.isSelected ? 1 : 0);
    hash = 47 * hash + Objects.hashCode(this.user);
    hash = 47 * hash + Objects.hashCode(this.password);
    hash = 47 * hash + Objects.hashCode(this.address);
    hash = 47 * hash + (int) (this.addressAsLong ^ (this.addressAsLong >>> 32));
    hash = 47 * hash + this.port;
    hash = 47 * hash + Objects.hashCode(this.vendor);
    hash = 47 * hash + Objects.hashCode(this.model);
    hash = 47 * hash + Objects.hashCode(this.OS);
    hash = 47 * hash + Objects.hashCode(this.description);
    hash = 47 * hash + Objects.hashCode(this.version);
    hash = 47 * hash + Objects.hashCode(this.hostName);
    hash = 47 * hash + Objects.hashCode(this.domain);
    hash = 47 * hash + Objects.hashCode(this.deviceType);
    hash = 47 * hash + Objects.hashCode(this.Location);
    hash = 47 * hash + Objects.hashCode(this.SerialNumber);
    // hash = 47 * hash + Objects.hashCode(this.parent);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final DefaultDevice other = (DefaultDevice) obj;
    if (this.isSelected != other.isSelected) {
        System.out.println("isSelected");
        return false;
    }
    if (this.addressAsLong != other.addressAsLong) {
        // System.out.println("long");
        return false;
    }
    if (this.port != other.port) {
        //System.out.println("port");
        return false;
    }
    if (!Objects.equals(this.user, other.user)) {
        // System.out.println("user");
        return false;
    }
    if (!Objects.equals(this.password, other.password)) {
        //System.out.println("pass");
        return false;
    }

    if (!Objects.equals(this.vendor, other.vendor)) {
        //System.out.println("ven");
        return false;
    }
    if (!Objects.equals(this.model, other.model)) {
        //System.out.println("mod");
        return false;
    }
    if (!Objects.equals(this.OS, other.OS)) {
        // System.out.println("os");
        return false;
    }
    if (!Objects.equals(this.description, other.description)) {
        //System.out.println("des");
        return false;
    }
    if (!Objects.equals(this.version, other.version)) {
        //System.out.println("ver");
        return false;
    }
    if (!Objects.equals(this.hostName, other.hostName)) {
        // System.out.println("hostNa");
        return false;
    }
    if (!Objects.equals(this.domain, other.domain)) {
        // System.out.println("dom");
        return false;
    }
    if (!Objects.equals(this.deviceType, other.deviceType)) {
        // System.out.println("dt");
        return false;
    }
    if (!Objects.equals(this.Location, other.Location)) {
        //System.out.println("loc");
        return false;
    }
    if (!Objects.equals(this.SerialNumber, other.SerialNumber)) {
        // System.out.println("sn");
        return false;
    }

    return true;
}

1 个答案:

答案 0 :(得分:1)

考虑到可访问性,使用getter / setter而不是字段访问等的综合解决方案需要相当多的努力,但在您所描述的范围内,算法可能如下所示:

  • 在你的方法中返回你的迭代类型的对象作为结果,并使用默认值作为不匹配的情况(如果你愿意,用Map<String, Object>替换那些)
  • 从非空集合中获取第一项并确定其类
  • 遍历所有声明的字段,每个字段从第一个项目获取值,然后通过项目迭代,直到第一个不匹配
  • 如果不匹配,则从默认值中指定值并中断迭代
  • 将找到的值设置为结果字段并移至下一个字段

在代码中它看起来像这样:

class ObjectMatcher {

    // NPE on null items
    // assumes public default constructor for T is available
    public <T> T match(Collection<T> items, T defaults) {
        if (items.isEmpty()) {
            return defaults;
        }
        try {
            @SuppressWarnings("unchecked")
            Class<T> clazz = (Class<T>) items.iterator().next().getClass();
            Field[] fields = clazz.getDeclaredFields();

            T res = clazz.newInstance();

            for (Field field : fields) {
                boolean firstItem = true;
                Object match = null;
                for (T item : items) {
                    Object value = field.get(item);
                    if (firstItem) {
                        match = value;
                    }
                    else if (!Objects.equals(value, match)) {
                        match = field.get(defaults);
                        break;
                    } // otherwise keep the match as is
                    firstItem = false;
                }
                field.set(res, match);
            }
            return res;
        }
        catch (IllegalAccessException | InstantiationException e) {
            throw new RuntimeException(e);
        }
    }
}

这是一个简单的测试,用于场不匹配,匹配和null /非null不匹配的情况:

@Test
public void match_onMistmatchMatchAndNull_ok() {
    Student s1 = new Student("Andrew", "Physics", null);
    Student s2 = new Student("Joe", "Physics", 3.45);
    Student s3 = new Student("Nicki", "Physics", 2.39);

    Student defaults = new Student("Multiple Names", "Multiple Courses", 1.0);

    ObjectMatcher matcher = new ObjectMatcher();
    Student res = matcher.match(Arrays.asList(s1, s2, s3), defaults);

    assertEquals("Multiple Names", res.name);
    assertEquals("Physics", res.course);
    assertEquals(1.0, res.grade.doubleValue(), 0.001);
}

您可以在dedicated GitHub repo上找到测试类的完整代码。