【问题标题】:setting objects equal to eachother (java)设置对象彼此相等(java)
【发布时间】:2015-06-15 21:24:15
【问题描述】:

所以我有一个名为 Person 的类,看起来像这样

public class Person {

    private String personName;


    public String toString(){
        return personName;
    }

    public Person(String personName){
        this.personName = personName;
    }

}

以及我在其中创建对象的另一个类人

public class IdanJavaTask {

    public static void main(String[] args) {

        Person p1 = new Person("Bob");
        System.out.println("p1 : " + p1);

        Person p2 = new Person("Joe");
        System.out.println("p2 :" + p2);

    }

}

到目前为止一切都很好,我的打印声明是
p1:鲍勃
p2:乔

现在我想创建一个新对象 p3 并将其设置为等于 p1 我的班级现在看起来像这样:

public class IdanJavaTask {

    public static void main(String[] args) {

        Person p1 = new Person("Bob");
        System.out.println("p1 : " + p1);

        Person p2 = new Person("Joe");
        System.out.println("p2 :" + p2);

        Person p3 = new Person (p1);
        System.out.println("p3 equal to p1:" + p3.equals(p1));

    }

}

当我尝试这样做时,我收到以下错误消息:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The constructor Person(Person) is undefined

    at vehicleassignment.IdanJavaTask.main(IdanJavaTask.java:13)

我想我需要向我的主(Person)类添加一个方法,但我不知道为什么或添加什么?为什么我不能将对象设置为彼此相等?

【问题讨论】:

    标签: java methods compiler-errors equals


    【解决方案1】:

    有两种解释“设置对象彼此相等”的方式。

    一个是您希望p1p3 引用同一个 对象。就像克拉克肯特和超人是同一个人的两个名字(参考)一样。这将通过以下方式完成:

    Person p1 = new Person("Jim");
    Person p3 = p1;
    

    在这种情况下,如果 p1 发生任何事情,p3 也会发生同样的事情。如果你杀了克拉克肯特,你就杀了超人(因为他们是一回事)。 Java 使用equals(Object o) 方法确定相等性——如果a.equals(b)b.equals(a) 返回true,则ab 两个对象相等。这两个对象将使用基本的Object 相等定义相等,因此您不必担心。

    另一种解释你的意思的方法是创建一个人对象,它恰好是第一人称的精确副本。为了做到这一点,你必须在你的 person 类中添加另一个构造函数,它将一个人作为参数:

    public class Person {
    
        private String personName;
    
        public String toString(){
            return personName;
        }
    
        public Person(String personName){
            this.personName = personName;
        }
    
        public Person(Person personToCopy){
            this.personName = personToCopy.personName;
        }
    
    }
    

    通过此设置,您可以在 main 中执行您正在执行的操作。

    Person p1 = new Person("Bob");
    Person p3 = new Person(p1); //Will have name Bob.
    

    为了使p1p3 相等,我们必须教Person 类使用它的字段来检查相等性。我们可以通过覆盖 person 类中的 equals 方法来做到这一点。

    public boolean equals(Object o){
        if(! (o instanceof Person)) return false; //a Person can't be equal to a non-person
    
        Person p = (Person) o;
        return personName == null && p.personName == null || personName.equals(p.personName);
    }
    

    每当我们覆盖equals 方法时,最好也覆盖hashcode 方法,它为每个对象返回一个唯一的int。由于Person 对象的唯一字段是它的名称,我们可以简单地使用该哈希码。

    public int hashCode(){
        return personName == null ? 0 : personName.hashCode();
    }
    

    所以,我们的 Person 类看起来像这样:

    public class Person {
    
        private String personName;
    
        public String toString(){
            return personName;
        }
    
        public Person(String personName){
            this.personName = personName;
        }
    
        public Person(Person personToCopy){
            this.personName = personToCopy.personName;
        }
    
        public boolean equals(Object o){
            if(! (o instanceof Person)) return false; //a Person can't be equal to a non-person
    
            Person p = (Person) o;
            return personName == null && p.personName == null || personName.equals(p.personName);
        }
    
        public int hashCode(){
            return personName == null ? 0 : personName.hashCode();
        }
    }
    

    【讨论】:

    • 在您的第一个示例中,如果我更改 p1 会怎样? p3 也会改变吗?
    【解决方案2】:
    Person p3 = new Person(p1);
    

    这被称为复制构造函数。在这种情况下,您需要明确定义它:

    public Person(Person p) {
        this.personName = p.personName;
    }
    

    您还需要重写equals()方法(和hashCode()方法)才能使用它,否则将使用根类Objectequals()方法,它总是返回false:

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

    What issues should be considered when overriding equals and hashCode in Java?

    【讨论】:

      【解决方案3】:

      Java 中的任何对象都没有默认的复制构造函数,除了自动装箱的对象,如 FloatInteger,它们确实被复制了。

      这意味着在任何情况下,您都有责任定义复制构造函数并指定复制的内容,在您的示例中:

      public Person(Person other) {
        this.personName = other.personName;
      }
      

      由于在 Java 中所有内容都是通过引用传递的,因此简单的赋值只会使 2 个变量指向同一个实例,例如:

      Person p1 = new Person("Joe");
      Person p2 = p1;
      // now both point to the same object, not intended behavior in your case
      

      【讨论】:

        【解决方案4】:

        如果您希望 p3 引用 p2,这意味着对 p2 的更改将更新 p3,反之亦然,只需这样做

        Person p3 = p2;
        

        如果您想克隆数据并拥有两个不同但“相等”的人员副本,您可以在 Person 中实现一个构造函数,该构造函数接受一个 Person 并将值复制到类字段中。

        【讨论】:

          【解决方案5】:

          这是因为您的 Person 类构造函数。您将它定义为仅接受 String 类型,并在实例化它时给它一个对象“p1”。编辑构造函数或新建一个即可解决。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-22
            • 2021-11-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-05-09
            相关资源
            最近更新 更多