所以我有一个名为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)
我想我需要在main(Person)类中添加一个方法,但我不知道为什么或要添加什么?为什么我不能将对象设置为彼此相等?
答案 0 :(得分:8)
有两种方法可以解释"将对象设置为彼此相等"。
一个是您希望p1
和p3
引用相同的对象。就像Clark Kent和Superman是同一个人的两个名字(参考)一样。这将通过以下方式实现:
Person p1 = new Person("Jim");
Person p3 = p1;
在这种情况下,如果p1
发生任何事情,p3
也会发生同样的事情。如果你杀死克拉克肯特,你已经杀死了超人(因为他们是同一个人)。 Java使用equals(Object o)
方法确定相等性 - 如果a
和b
返回a.equals(b)
,则两个对象b.equals(a)
和true
相等。使用基本Object
平等定义,这两个对象将是相同的,因此您不必担心这一点。
解释你的意思的另一种方法是创建一个 new person对象,它恰好是第一个人的精确副本。为了做到这一点,你必须在你的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;
}
}
通过此设置,您可以执行主要操作。
Person p1 = new Person("Bob");
Person p3 = new Person(p1); //Will have name Bob.
为了使p1
和p3
相等,我们必须教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();
}
}
答案 1 :(得分:3)
Person p3 = new Person(p1);
这称为复制构造函数。在这种情况下,您需要明确定义它:
public Person(Person p) {
this.personName = p.personName;
}
您还需要覆盖equals()
方法(以及hashCode()
方法)才能使用它,否则根类equals()
的{{1}}方法将是used,总是返回false:
Object
请参阅What issues should be considered when overriding equals and hashCode in Java?。
答案 2 :(得分:1)
Java中的任何对象都没有默认的复制构造函数,除了Float
或Integer
之类的自动装帧对象,这些对象确实被复制了。
这意味着在所有情况下,您都有责任在您的示例中定义复制构造函数并指定复制的内容:
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
答案 3 :(得分:0)
如果您希望p3引用p2,意味着更改p2将更新p3,反之亦然,只需执行
Person p3 = p2;
如果你想克隆数据并拥有两个截然不同但相同的人物副本,你可以在Person中实现一个构造函数,它接受一个Person并将值复制到classes字段中。
答案 4 :(得分:0)
这是因为您的Person类构造函数。您将其定义为仅接受String类型,并在实例化它时为其指定了对象“ p1”。编辑构造函数或创建一个新的构造函数即可解决。