Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在equals()中包含非公共字段是一种不好的做法吗_Java - Fatal编程技术网

Java 在equals()中包含非公共字段是一种不好的做法吗

Java 在equals()中包含非公共字段是一种不好的做法吗,java,Java,在equals()中包含任何公共方法都无法访问的字段(这些字段本身不是也不能从任何其他公共字段派生)是否是一种不良做法 这样做可能产生什么不良后果 这是否被描述为某个地方的不良做法? (我假设hash/equals契约是可以的) 我觉得这样的等于在哲学上是非常错误的。这种等于在世界上是不存在的。但是,撇开哲学不谈,它会导致真正的编程错误行为吗?我能想到一个坏的结果——类的用户可能会比较两个对象,其中所有公共可访问属性都是相等的,他们不会理解为什么equals方法返回false 我假设(您的编辑确

equals()
中包含任何公共方法都无法访问的字段(这些字段本身不是也不能从任何其他公共字段派生)是否是一种不良做法

这样做可能产生什么不良后果

这是否被描述为某个地方的不良做法? (我假设hash/equals契约是可以的)


我觉得这样的等于在哲学上是非常错误的。这种等于在世界上是不存在的。但是,撇开哲学不谈,它会导致真正的编程错误行为吗?

我能想到一个坏的结果——类的用户可能会比较两个对象,其中所有公共可访问属性都是相等的,他们不会理解为什么
equals
方法返回false


我假设(您的编辑确认了这一点)您指的是没有公共访问权限的私有字段(即没有getter),因为一般来说,所有属性都应该是私有的,并且只能由setter和getter访问。

您应该放入使对象唯一的字段。如果可以修改,则字段的重要性较小。

没关系。如果您自己编写类,用户仍然可以使用您可能添加的getter和setter方法获取和设置字段。但是,如果添加getter和setter方法,请确保字段是安全的

如果您没有编写getter和setter方法,用户可能很难根据所有公共字段的值确定对象不相等的原因。话虽如此,您可能可以使用调试器逐步遍历私有字段的所有值


另一种可能性是创建一个特殊的方法,该方法将返回不相等的特定字段。尽管这并不严格符合“任何公共方法都无法访问”字段的要求,但返回动态创建的字符串、基本类型或对象(如字段名数组)将确保方法的安全。

这是绝对正确的,有时也是必要的。唯一不应该比较的字段是标记为
transient
的字段

我断言两个实例是相等的,当且仅当它们的序列化相等时。这就是为什么
transient
很重要,而字段封装的程度并不重要。

应该在
equals()
中做什么? 有些字段定义对象的标识,有些字段定义对象的属性。手机的序列号是其身份的一部分,其颜色或电池电量百分比只是一种属性

equals()
应该只依赖于定义标识的字段,这与字段是否可以从外部访问无关,它来自字段本身的语义

所以问题应该是:有没有任何理由对其客户机隐藏对象的身份?如果答案似乎是“是”,那么下一个更基本的问题是:有没有理由首先识别这些物体?毕竟,有很多对象不需要在琐碎之外有一个身份

有几个可能的问题由此产生,这里有一个例子

问题实例 现在想象一下,一个天真的客户想要把这些放到
树集中。该类没有可比性,但无需担心,我们可以为其编写一个比较器:

public class FooComparator implements Comparator<Foo> {

    public int compare( Foo first, Foo second ) {
        return first.getAccessible().compareTo( second.getAccessible() );
    }
}

然后将
Helper
对象放在
HashSet
中,而不是
Foo
。尽管
Helper
s可见性是包私有的,但在大多数情况下仍然可以接受,因为此级别不是公共API的一部分。

使用公共字段是不好的做法:)为什么不好?我不记得我上一次看到公共领域()是什么时候了。@Alex:所以在这种情况下,它太宽泛了,但我个人认为这样做的影响是否是负面的,这在很大程度上取决于情况too@Alex:如果有100个例子说明它如何产生负面影响呢?再说一次,谁来决定效果是否是负面的?@Alex:如果你不能证明,那么也许你有一个这样做的场景。例如,假设您有一个私有字段,它实际上存储了某种“元信息”(它可能是一些昂贵计算的缓存),不需要是公共的,但对于检查相等性很重要。。。再一次。。。这么多的可能性。也许你应该找一个聊天室来进行这样的讨论这有点误导。如果一个类的用户需要检查该类的两个实例是否相等,则应该使用
equals
,而不是一些自制的属性比较方法。因为,OOP是关于状态和行为的,两个对象的相等性应该由状态决定,状态包括所有成员的值,公共的或私有的。@Krumia假设我编写代码:
。。。字符串str=“foo”;字符串str2=“foo”;if(str.equals(str2)){…}else{…}…
如果执行
else
子句,我会非常惊讶。@Eran:您会感到惊讶,因为字符串不是这样设计的。OP指的是定制类,它可能有许多不同的数据属性来确定相等性,并且并非所有的都需要公开。关键是,平等的规则是由规范决定的。。。哪一种可能anything@Eran:我也会的。如果您遇到OP描述的此问题,则必须满足以下条件之一:1。您尚未公开本应使用getter公开的成员。通过getter公开实例成员。2.您已将方法中本应为局部变量的内容提升为实例变量。将该实例成员降级为相关方法的局部变量。3.您必须使用实例成员,因为您不必要地拆分了一个方法。所以为了传递状态,您需要实例成员。这是退出
public class FooComparator implements Comparator<Foo> {

    public int compare( Foo first, Foo second ) {
        return first.getAccessible().compareTo( second.getAccessible() );
    }
}
public class Foo {
    private Bar hidden;
    private String accessible;
    private final Helper helper = new Helper();


    Helper helper() {
       return helper;
    }      

    class Helper {

        @Override
        public boolean equals( Object ob ) {
          // you can access "hidden" from here
        }

        @Override
        public int hashCode() {
          // you can access "hidden" from here
        }

        public Foo foo() {
            return Foo.this;
        }
    }
}