Java 除了比较两个对象的相等性,还有什么替代方法?

Java 除了比较两个对象的相等性,还有什么替代方法?,java,equals,Java,Equals,事实证明,定义equals() 不是琐碎的;事实上,这是适度的 很难做到正确,尤其是在 子类的情况。最好的 对这些问题的处理正在进行中 霍斯特曼的核心Java第1卷 如果必须始终重写equals(),那么,有什么好方法可以避免被迫进行对象比较呢?哪些是好的“设计”备选方案 编辑: 我不确定这是否是我的初衷。也许这个问题应该更接近于“你为什么要比较两个物体?”根据你对这个问题的回答,有没有替代方案来进行比较?我不是说,平等的不同实现。我的意思是,根本不使用平等。我认为关键点是从这个问题开始,你为什

事实证明,定义equals() 不是琐碎的;事实上,这是适度的 很难做到正确,尤其是在 子类的情况。最好的 对这些问题的处理正在进行中 霍斯特曼的核心Java第1卷

如果必须始终重写equals(),那么,有什么好方法可以避免被迫进行对象比较呢?哪些是好的“设计”备选方案

编辑:

我不确定这是否是我的初衷。也许这个问题应该更接近于“你为什么要比较两个物体?”根据你对这个问题的回答,有没有替代方案来进行比较?我不是说,平等的不同实现。我的意思是,根本不使用平等。我认为关键点是从这个问题开始,你为什么要比较两个物体。

Mmhh

在某些情况下,可以使对象不可修改(只读),并从单个点创建它(工厂方法)

如果需要两个具有相同输入数据(创建参数)的对象,工厂将返回相同的实例引用,然后使用“==”就足够了

这种方法仅在某些情况下有用。而且大多数时候看起来都太过分了

看一看就知道如何实现这样的事情

警告:代码太多了

简而言之,请参见包装器类的工作原理

这是真的

new Integer( 2 ) == new Integer( 2 )  
这是错误的

它在内部保留引用,如果输入值相同,则返回引用

正如您所知,整数是只读的


类似的情况也发生在这个问题所涉及的String类中。

如何正确处理它

这是我的equals模板,它是Josh Bloch从有效Java应用的知识。阅读本书了解更多详细信息:

@Override
public boolean equals(Object obj) {
    if(this == obj) {
        return true;
    }

    // only do this if you are a subclass and care about equals of parent
    if(!super.equals(obj)) {
        return false;
    }
    if(obj == null || getClass() != obj.getClass()) {
        return false;
    }
    final YourTypeHere other = (YourTypeHere) obj;
    if(!instanceMember1.equals(other.instanceMember1)) {
       return false;
     }
     ... rest of instanceMembers in same pattern as above....
     return true;
 }

我认为平等不应该总是被忽视。我理解的规则是,只有在清楚如何定义语义等价的对象的情况下,重写equals才有意义。在这种情况下,还可以重写hashCode(),这样就不会有定义为等价的对象返回不同的hashCode


如果你不能定义有意义的等价,我看不出有什么好处

也许我没有抓住要点,但是使用equals而不是用不同的名称定义自己的方法的唯一原因是因为许多集合(可能还有JDK中的其他东西,或者现在叫什么)都希望equals方法定义一致的结果。但除此之外,我可以想到三种你想在同等条件下进行的比较:

  • 这两个对象实际上是同一个实例。使用equals没有任何意义,因为您可以使用==。另外,如果我忘记了它在Java中是如何工作的,请纠正我,默认的equals方法使用自动生成的哈希代码来实现这一点
  • 这两个对象引用了相同的实例,但不是相同的实例。这是有用的,嗯,有时候。。。特别是当它们是持久化对象并且在数据库中引用同一对象时。您必须定义equals方法才能执行此操作
  • 这两个对象对值相等的对象具有引用,尽管它们可能是也可能不是相同的实例(换句话说,可以在整个层次结构中对值进行比较)
  • 为什么要比较两个对象?如果他们相等,你会想做一件事,如果他们不相等,你会想做其他的事

    也就是说,这取决于手头的情况

    如果必须始终重写equals(), 那么,什么是一个好的方法 被迫做某事 对象比较

    你错了。您应该尽可能少地重写equals


    所有这些信息都来自()。关于这一点的第一版章节仍然是免费的

    来自有效Java:

    避免问题的最简单方法是 在中,不重写equals方法 在这种情况下,类的每个实例 它只与自身相等

    任意重写equals/hashCode的问题是继承。一些equals实现提倡这样测试:

    if (this.getClass() != other.getClass()) {
        return false; //inequal
    }
    
    事实上,(3.4)Java编辑器在您使用源工具生成方法时就是这样做的。根据布洛赫的说法,这是一个错误,因为它违反了法律

    来自有效Java:

    没有办法延长期限 实例化类并添加一个值 保持相等时的分量 合同

    类和接口一章中介绍了两种最小化相等问题的方法:

  • 重组合轻继承
  • 继承的设计和文档,否则禁止继承

  • 就我所见,唯一的替代方法是在类外部的形式中测试相等性,如何执行取决于类型的设计和您试图在其中使用它的上下文

    例如,您可以定义一个接口来记录如何对其进行比较。在下面的代码中,服务实例可能在运行时被同一类的较新版本所替换-在这种情况下,如果有不同的类加载器,equals比较将始终返回false,因此重写equals/hashCode将是多余的

    public class Services {
    
        private static Map<String, Service> SERVICES = new HashMap<String, Service>();
    
        static interface Service {
            /** Services with the same name are considered equivalent */
            public String getName();
        }
    
        public static synchronized void installService(Service service) {
            SERVICES.put(service.getName(), service);
        }
    
        public static synchronized Service lookup(String name) {
            return SERVICES.get(name);
        }
    }
    
    公共类服务{
    私有静态映射服务=newhashmap();
    静态接口服务{
    /**具有相同名称的服务被认为是等效的*/
    公共字符串getName();
    }
    公共静态同步无效安装服务(服务服务){
    SERVICES.put(service.getName(),service);
    }
    公共静态同步服务查找(字符串名称){
    return SERVICES.get(名称);
    }
    }
    

    “为什么要比较两个对象?”

    一个明显的例子是测试两个字符串
    public class Services {
    
        private static Map<String, Service> SERVICES = new HashMap<String, Service>();
    
        static interface Service {
            /** Services with the same name are considered equivalent */
            public String getName();
        }
    
        public static synchronized void installService(Service service) {
            SERVICES.put(service.getName(), service);
        }
    
        public static synchronized Service lookup(String name) {
            return SERVICES.get(name);
        }
    }
    
    Adding duplicates to a map (bad):
    Result of map.get(bean1):first
    Result of map.get(bean2):second
    Result of map.get(new NameBean("Alice"): null
    
    Adding duplicates to a map (good):
    Result of map.get(bean1):second
    Result of map.get(bean2):second
    Result of map.get(new ImprovedNameBean("Alice"): second
    
    // This bean cannot safely be used as a key in a Map
    public class NameBean {
        private String name;
        public NameBean() {
        }
        public NameBean(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return name;
        }
    }
    
    // This bean can safely be used as a key in a Map
    public class ImprovedNameBean extends NameBean {
        public ImprovedNameBean(String name) {
            super(name);
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if(obj == null || getClass() != obj.getClass()) {
                return false;
            }
            return this.getName().equals(((ImprovedNameBean)obj).getName());
        }
        @Override
        public int hashCode() {
            return getName().hashCode();
        }
    }
    
    public class MapDuplicateTest {
        public static void main(String[] args) {
            MapDuplicateTest test = new MapDuplicateTest();
            System.out.println("Adding duplicates to a map (bad):");
            test.withDuplicates();
            System.out.println("\nAdding duplicates to a map (good):");
            test.withoutDuplicates();
        }
        public void withDuplicates() {
            NameBean bean1 = new NameBean("Alice");
            NameBean bean2 = new NameBean("Alice");
    
            java.util.Map<NameBean, String> map
                    = new java.util.HashMap<NameBean, String>();
            map.put(bean1, "first");
            map.put(bean2, "second");
            System.out.println("Result of map.get(bean1):"+map.get(bean1));
            System.out.println("Result of map.get(bean2):"+map.get(bean2));
            System.out.println("Result of map.get(new NameBean(\"Alice\"): "
                    + map.get(new NameBean("Alice")));
        }
        public void withoutDuplicates() {
            ImprovedNameBean bean1 = new ImprovedNameBean("Alice");
            ImprovedNameBean bean2 = new ImprovedNameBean("Alice");
    
            java.util.Map<ImprovedNameBean, String> map
                    = new java.util.HashMap<ImprovedNameBean, String>();
            map.put(bean1, "first");
            map.put(bean2, "second");
            System.out.println("Result of map.get(bean1):"+map.get(bean1));
            System.out.println("Result of map.get(bean2):"+map.get(bean2));
            System.out.println("Result of map.get(new ImprovedNameBean(\"Alice\"): "
                    + map.get(new ImprovedNameBean("Alice")));
        }
    }