setting objects equal to eachother (java)

43k views Asked by At

So I have a class called Person which looks like this

public class Person {

    private String personName;


    public String toString(){
        return personName;
    }

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

}

and another class in which I am creating the object(s) person

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);

    }

}

so far everything is fine and my print statement is
p1: Bob
p2: Joe

Now I want to create a new object, p3 and set it equal to p1 my class now looks like this:

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));

    }

}

when I try to do this I get the following error message:

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

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

I am thinking I will need to add a method to my main (Person) class, but I do not know why or what to add? why can't I just set the objects equal to eachother?

5

There are 5 answers

1
Mshnik On BEST ANSWER

There are two ways to interpret "set the objects equal to each other".

One is that you want p1 and p3 to refer to the same object. Like how Clark Kent and Superman are two names (references) for the same person. This would be accomplished by:

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

In this scenario, if anything happens to p1, that same thing has happened to p3. If you kill Clark Kent, you have killed Superman (as they are one and the same). Java determines equality with the equals(Object o) method - two objects a and b are equal iff a.equals(b) and b.equals(a) return true. These two objects will be equal using the base Object definition of equality, so you don't have to worry about that.

The other way to interpret your meaning is to create a new person object, which happens to be an exact copy of the first person. In order to do this, you'd have to add another constructor to your person class that takes a person as an argument:

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;
    }

}

With this setup, you can do what you're doing in your main.

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

In order to make p1 and p3 equal, we have to teach the Person class to use its fields for checking equality. We can do this by overriding the equals method in class person.

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);
}

Whenever we overwrite the equals method, it is good practice to also overwrite the hashcode method, which returns a unique int for each Object. Since the only field that a Person object has is its name, we can simply use that hashcode.

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

So all together, our Person class looks like this:

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();
    }
}
0
M A On
Person p3 = new Person(p1);

This is known as a copy constructor. You'll need to define it explicitly, in this case:

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

You also need to override the equals() method (and the hashCode() method) in order to use it, otherwise the equals() method of the root class Object would be used, which always returns 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;
}

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

0
Mark W On

If you want p3 to reference p2, meaning a change to p2 will update p3 and vice versa, just do

Person p3 = p2;

if you want to clone the data and have two distinct, but 'equal' copies of the person, you can implement a constructor in Person that takes a Person and copies the values into the classes fields.

0
Jack On

No object in Java has a default copy constructor, with the exception of autoboxed objects like Float or Integer which are indeed copied.

This means that under all circumstances it's your duty to define a copy constructor and specify what is copied, in your example:

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

Since in Java everything is passed by reference a plain assignment would just make 2 variables point to the same instance, eg:

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

It is because of your Person class constructor. You defined it to accept String type only and you gave it an object "p1" when you instantiate it. Editing the constructor or creating a new one will solve it.