从构造函数构造链接的 Java 对象
Constructing linked Java objects from constructors
我一直在努力解决 OOD 问题,这让我很沮丧。我正在尝试构建一个包含三个 classes 的程序 - 一个名为 Person 的程序将具有由个人信息组成的构造函数。另一个名为 Doctor 的 class 继承了 Person class 并简单地构造了一个带有额外字段(大多数字段,即姓名,地址将指向 person 对象)的对象,称为 specialty。我使用另一个 class 构建 java 应用程序来创建、查看和修改 person 和 doctor 对象中的字段。
我已经构建了人和医生 classes,你可以在这个 post 的底部找到他们的相关代码。当我尝试创建 doctor 对象时出现问题,因为我的代码似乎正在创建一个与 person 对象没有任何关系的全新 doctor 对象。我试图编辑一个人对象的 firstName 字符串,但医生对象没有更新以反映这一点。它似乎已经创建了自己的永久名称,而不是简单地指向 person 对象中定义的名称。
我通过用户输入创建人物对象并使用以下行存储它们。
persons[amountPersons] = new Person (firstName, lastName, homeAddress, phoneNumber);
amountPersons++;
创建人员对象后,用户可以输入人员编号并像这样创建医生对象
person = getPersonID(personID);
int personNumber;
String firstName = null;
String lastName = null;
String homeAddress = null;
String phoneNumber = null;
firstName = person.firstName;
lastName = person.lastName;
homeAddress = person.homeAddress;
phoneNumber = person.phoneNumber;
personNumber = person.personNumber;
System.out.print ("Enter speciality of the doctor: ");
String speciality = input.nextLine();
doctors[amountDoctors] = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality);
amountDoctors++;
我究竟做错了什么?为大量代码道歉 - 我已尽我所能精简它,但我不确定问题出在哪里,所以我只能做这么多。
人Class
public class Person {
//Instance Variables
protected String firstName;
protected String lastName;
protected String homeAddress;
protected String phoneNumber;
protected int personNumber;
private static int NumberSystem = 1;
public Person()
{
firstName = " ";
lastName = " ";
homeAddress = " ";
phoneNumber = " ";
personNumber = 0;
}
public Person (String firstName, String lastName, String homeAddress, String phoneNumber)
{
// Initialize instance variables
this.firstName = firstName;
this.lastName = lastName;
this.homeAddress = homeAddress;
this.phoneNumber = phoneNumber;
personNumber = NumberSystem;
NumberSystem = NumberSystem + 1;
}
public String toString()
{
String p;
p = "=================================================" +"\n" +
"Identification Number: " + personNumber +"\n" +
"Name: " + firstName +"\n" +
"Surname: " + lastName +"\n" +
"Address: " + homeAddress +"\n" +
"Mobile/Telephone: " + phoneNumber +"\n";
return p;
}
医生
public class Doctor extends Person{
// the aim of Doctor subclass is to simply add a speciality field
private String speciality;
int doctorID;
public Doctor() {
doctorID = 0;
speciality = "none";
}
public Doctor(String firstName, String lastName, String homeAddress, String phoneNumber, String speciality) {
super(firstName, lastName, homeAddress, phoneNumber);
this.speciality = speciality;
}
public String toString()
{
String d;
d = "=================================================" +"\n" +
"Doctor Number: " + doctorID +"\n" +
"Person Number: " + personNumber +"\n" +
"Name: " + firstName +"\n" +
"Surname: " + lastName +"\n" +
"Address: " + homeAddress +"\n" +
"Mobile/Telephone: " + phoneNumber +"\n" +
"Speciality: " + speciality +"\n";
return d;
}
}
你用person = getPersonID(personID);
得到的人和你用doctors[amountDoctors] = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality)
创造的医生是完全不同的对象。
只是因为他们有相同的例子firstName等不代表对象有任何关系
您可以通过多种方式解决这个问题。例如,您不能创建一个 Person 后跟一个 Doctor,而只能创建一个 Doctor。然而,这并不能反映现实生活,因此您可以用 Doctor 替换存储在数组中的 Person。
Person[] people = // however you initialise it;
Doctor[] doctors // however you initialise it;
既然Doctor也是Person,你可以直接说people[i] = doctor
。根据您上面的代码,它可能包含在这样的方法调用中:
// I'm assuming personID is an int, but you may need to adapt this
private void replacePerson(int personID,
Person person) {
int index = // get index of personID from the array
people[index] = person;
}
并用
调用它
Doctor doctor = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality);
doctors[amountDoctors] = doctor;
amountDoctors++;
replacePerson(personID, doctor);
在设计两个相互关联的对象时,有两种常用的模式。
继承。继承是一个强大的工具,但它不是万灵药,它有自己的问题和局限性。如果 Class B 与 Class A 有 is a 关系,你应该只使用继承。例如,一辆山地自行车是一辆自行车,所以它是明智的拥有一辆 MountainBike
class extend
`自行车'。如果你不能说存在 "is a" 关系,那么不要使用继承。
作文。组合也是一个强大的工具,可以说它比继承更健壮,更不脆弱。当 Class B 是 Class A 的属性时(或当 Class A 有一个 Class B 时使用组合。在这种情况下,您正在使 Class B 成为 Class A.
的实例字段
在你描述的模型中,医生是一个人,所以使用继承似乎很明智。由于我们只能看到您显示的两个 class 域模型,因此我也会选择让 Doctor 扩展 Person。
作为一种风格问题,您应该养成使用 @Override
注释的习惯,只要您打算覆盖基类 class 中的方法。当您这样做时,编译器会提醒您否则很难发现错误。您应该使用 @Override
.
注释 toString()
方法(继承自 Object
)
The problem occurs when I try creating doctor objects as my code seems
to be creating an entirely new doctor object with no relation
whatsoever to the person object.
当您使用
创建 Doctor 实例时
Doctor doc = new Doctor(...);
你得到的对象既是它自己的类型,也是它父级的类型,例如。医生是医生,医生是人。以下是合法的:
Person person = new Doctor(...);
您可以将子class 中的对象分配给其超类型(或父类)的变量。没有创建新的 Person 对象,只有 Doctor 对象(可以分配给 Person 变量,因为医生是一个人)。
这是不允许的:
Doctor doc = new Person(...);
所有医生都是人,但是...并非所有人都是医生,所以这个分配会有问题。编译器不会让你这么做的。
一旦你创建了一个Doctor
它就会得到他自己的成员变量。这样想:
你有一个 Person
,在他那很棒的夹克上有铭牌、地址牌等。现在你把这个 Person
交给他的盘子。之后你想把他提升为 Doctor
,但由于 Doctor
继承了 Person
他也有自己的铭牌、地址牌等。
他们没有分享它。
所以你想做的是使用Composition
。
例如
public class Doctor(){
private Person person;
private String speciality;
public Doctor(Person person, speciality){
this.person = person;
this.speciality = speciality;
}
}
现在,如果您更改 Person
的名字,它也会更新所有指向那个人的 Doctors
的名字。
发生的就是应该发生的。医生是人,但人不是医生。
现在,当您创建一个 Person 对象时,您会创建一个 class Person 的实例,并将它作为一个对象放在堆上。
然后您从该对象中检索各种字段,这次您使用它们来初始化 Doctor 的一个新实例,并将这个新对象放入堆中。这是一个 Doctor 类型的独特新对象,它也是 Person 类型,但它 不是 您创建的旧 Person 对象。这就是继承。按照您期望的方式工作将是灾难性的。
组合不是解决您问题的正确方法,因为它没有意义,因为医生 是一个 人而不是 有一个 人。
你可以做的是使用 Decorator 模式并让 Doctor 成为 Person 可以或不可以拥有的属性。一个好的教程是 this
您似乎期望继承的行为不会发生。 Doctor 对象与单独的 Person 对象没有任何关系。它 Doctor 是一个 Person,因此它包含 Person 中定义的所有字段,以及 Doctor.
中定义的字段。
- Your person[] 数组可以存储 Person 和 Doctor 类。但是如果你使用
new Person()
创建成员,他们将永远不会是医生。
- 不清楚为什么你有一个 Person 数组和一个 Doctor 数组。
- 继承是一个编译时概念。听起来您希望在运行时同时拥有医生的 Person 记录和 Doctor 记录。您将只有一个 Doctor 记录,由于继承,它将包含所有 Person 字段。
可能有点跑题了,你应该重新考虑继承是否是正确的方法。 @Dragondraikk 的评论是准确的。在我看来,"Is a" 继承测试应该被 "Is a for the life of the application" 取代。作为一名医生是一个人扮演的有时间限制的角色。这指向使用组合。这样,一个人一旦符合资格就可以成为医生,如果他们被取消资格,就可以恢复为一个人。在对象的生命周期中更改对象的具体类型从来都不是一个好主意。
如果我误解了您的问题,请提前致歉。
当Doctor对象存入内存后,就会进行分配
对于 superclass(Person)中的字段,然后是 Doctor class.
中的字段
所以当医生对象存储在内存中时,它是一个完整的对象而不是
一半是人,一半是医生。
JVM 对象知道连接到 Doctor 对象内存分配的结构是 Doctor 对象的唯一方法是通过
标记为 "native pointer to class information."
的 4 字节数量
类型安全转换和 instanceof 运算符等使用此信息来确定此内存分配属于哪个 class 结构
到.
所以是的,确实是继承关系,如前所述
回答因为医生是一个人(如果医生有病人那么它就是组合)
Bill Venners 的这篇文章对该主题进行了更详细的解释。
http://www.artima.com/designtechniques/initializationP.html
更重要的一点是,即使 Person 有私有变量,在 Doctor 中仍然无法直接访问,当内存分配给
Doctor 对象有分配给私有变量的内存
清楚地表明 super 和 sub class 的整个变量集
一起构成子class.
我一直在努力解决 OOD 问题,这让我很沮丧。我正在尝试构建一个包含三个 classes 的程序 - 一个名为 Person 的程序将具有由个人信息组成的构造函数。另一个名为 Doctor 的 class 继承了 Person class 并简单地构造了一个带有额外字段(大多数字段,即姓名,地址将指向 person 对象)的对象,称为 specialty。我使用另一个 class 构建 java 应用程序来创建、查看和修改 person 和 doctor 对象中的字段。
我已经构建了人和医生 classes,你可以在这个 post 的底部找到他们的相关代码。当我尝试创建 doctor 对象时出现问题,因为我的代码似乎正在创建一个与 person 对象没有任何关系的全新 doctor 对象。我试图编辑一个人对象的 firstName 字符串,但医生对象没有更新以反映这一点。它似乎已经创建了自己的永久名称,而不是简单地指向 person 对象中定义的名称。
我通过用户输入创建人物对象并使用以下行存储它们。
persons[amountPersons] = new Person (firstName, lastName, homeAddress, phoneNumber);
amountPersons++;
创建人员对象后,用户可以输入人员编号并像这样创建医生对象
person = getPersonID(personID);
int personNumber;
String firstName = null;
String lastName = null;
String homeAddress = null;
String phoneNumber = null;
firstName = person.firstName;
lastName = person.lastName;
homeAddress = person.homeAddress;
phoneNumber = person.phoneNumber;
personNumber = person.personNumber;
System.out.print ("Enter speciality of the doctor: ");
String speciality = input.nextLine();
doctors[amountDoctors] = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality);
amountDoctors++;
我究竟做错了什么?为大量代码道歉 - 我已尽我所能精简它,但我不确定问题出在哪里,所以我只能做这么多。
人Class
public class Person {
//Instance Variables
protected String firstName;
protected String lastName;
protected String homeAddress;
protected String phoneNumber;
protected int personNumber;
private static int NumberSystem = 1;
public Person()
{
firstName = " ";
lastName = " ";
homeAddress = " ";
phoneNumber = " ";
personNumber = 0;
}
public Person (String firstName, String lastName, String homeAddress, String phoneNumber)
{
// Initialize instance variables
this.firstName = firstName;
this.lastName = lastName;
this.homeAddress = homeAddress;
this.phoneNumber = phoneNumber;
personNumber = NumberSystem;
NumberSystem = NumberSystem + 1;
}
public String toString()
{
String p;
p = "=================================================" +"\n" +
"Identification Number: " + personNumber +"\n" +
"Name: " + firstName +"\n" +
"Surname: " + lastName +"\n" +
"Address: " + homeAddress +"\n" +
"Mobile/Telephone: " + phoneNumber +"\n";
return p;
}
医生
public class Doctor extends Person{
// the aim of Doctor subclass is to simply add a speciality field
private String speciality;
int doctorID;
public Doctor() {
doctorID = 0;
speciality = "none";
}
public Doctor(String firstName, String lastName, String homeAddress, String phoneNumber, String speciality) {
super(firstName, lastName, homeAddress, phoneNumber);
this.speciality = speciality;
}
public String toString()
{
String d;
d = "=================================================" +"\n" +
"Doctor Number: " + doctorID +"\n" +
"Person Number: " + personNumber +"\n" +
"Name: " + firstName +"\n" +
"Surname: " + lastName +"\n" +
"Address: " + homeAddress +"\n" +
"Mobile/Telephone: " + phoneNumber +"\n" +
"Speciality: " + speciality +"\n";
return d;
}
}
你用person = getPersonID(personID);
得到的人和你用doctors[amountDoctors] = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality)
创造的医生是完全不同的对象。
只是因为他们有相同的例子firstName等不代表对象有任何关系
您可以通过多种方式解决这个问题。例如,您不能创建一个 Person 后跟一个 Doctor,而只能创建一个 Doctor。然而,这并不能反映现实生活,因此您可以用 Doctor 替换存储在数组中的 Person。
Person[] people = // however you initialise it;
Doctor[] doctors // however you initialise it;
既然Doctor也是Person,你可以直接说people[i] = doctor
。根据您上面的代码,它可能包含在这样的方法调用中:
// I'm assuming personID is an int, but you may need to adapt this
private void replacePerson(int personID,
Person person) {
int index = // get index of personID from the array
people[index] = person;
}
并用
调用它Doctor doctor = new Doctor (firstName, lastName, homeAddress, phoneNumber, speciality);
doctors[amountDoctors] = doctor;
amountDoctors++;
replacePerson(personID, doctor);
在设计两个相互关联的对象时,有两种常用的模式。
继承。继承是一个强大的工具,但它不是万灵药,它有自己的问题和局限性。如果 Class B 与 Class A 有 is a 关系,你应该只使用继承。例如,一辆山地自行车是一辆自行车,所以它是明智的拥有一辆
MountainBike
classextend
`自行车'。如果你不能说存在 "is a" 关系,那么不要使用继承。作文。组合也是一个强大的工具,可以说它比继承更健壮,更不脆弱。当 Class B 是 Class A 的属性时(或当 Class A 有一个 Class B 时使用组合。在这种情况下,您正在使 Class B 成为 Class A.
的实例字段
在你描述的模型中,医生是一个人,所以使用继承似乎很明智。由于我们只能看到您显示的两个 class 域模型,因此我也会选择让 Doctor 扩展 Person。
作为一种风格问题,您应该养成使用 @Override
注释的习惯,只要您打算覆盖基类 class 中的方法。当您这样做时,编译器会提醒您否则很难发现错误。您应该使用 @Override
.
toString()
方法(继承自 Object
)
The problem occurs when I try creating doctor objects as my code seems to be creating an entirely new doctor object with no relation whatsoever to the person object.
当您使用
创建 Doctor 实例时Doctor doc = new Doctor(...);
你得到的对象既是它自己的类型,也是它父级的类型,例如。医生是医生,医生是人。以下是合法的:
Person person = new Doctor(...);
您可以将子class 中的对象分配给其超类型(或父类)的变量。没有创建新的 Person 对象,只有 Doctor 对象(可以分配给 Person 变量,因为医生是一个人)。
这是不允许的:
Doctor doc = new Person(...);
所有医生都是人,但是...并非所有人都是医生,所以这个分配会有问题。编译器不会让你这么做的。
一旦你创建了一个Doctor
它就会得到他自己的成员变量。这样想:
你有一个 Person
,在他那很棒的夹克上有铭牌、地址牌等。现在你把这个 Person
交给他的盘子。之后你想把他提升为 Doctor
,但由于 Doctor
继承了 Person
他也有自己的铭牌、地址牌等。
他们没有分享它。
所以你想做的是使用Composition
。
例如
public class Doctor(){
private Person person;
private String speciality;
public Doctor(Person person, speciality){
this.person = person;
this.speciality = speciality;
}
}
现在,如果您更改 Person
的名字,它也会更新所有指向那个人的 Doctors
的名字。
发生的就是应该发生的。医生是人,但人不是医生。
现在,当您创建一个 Person 对象时,您会创建一个 class Person 的实例,并将它作为一个对象放在堆上。
然后您从该对象中检索各种字段,这次您使用它们来初始化 Doctor 的一个新实例,并将这个新对象放入堆中。这是一个 Doctor 类型的独特新对象,它也是 Person 类型,但它 不是 您创建的旧 Person 对象。这就是继承。按照您期望的方式工作将是灾难性的。
组合不是解决您问题的正确方法,因为它没有意义,因为医生 是一个 人而不是 有一个 人。
你可以做的是使用 Decorator 模式并让 Doctor 成为 Person 可以或不可以拥有的属性。一个好的教程是 this
您似乎期望继承的行为不会发生。 Doctor 对象与单独的 Person 对象没有任何关系。它 Doctor 是一个 Person,因此它包含 Person 中定义的所有字段,以及 Doctor.
中定义的字段。- Your person[] 数组可以存储 Person 和 Doctor 类。但是如果你使用
new Person()
创建成员,他们将永远不会是医生。 - 不清楚为什么你有一个 Person 数组和一个 Doctor 数组。
- 继承是一个编译时概念。听起来您希望在运行时同时拥有医生的 Person 记录和 Doctor 记录。您将只有一个 Doctor 记录,由于继承,它将包含所有 Person 字段。
可能有点跑题了,你应该重新考虑继承是否是正确的方法。 @Dragondraikk 的评论是准确的。在我看来,"Is a" 继承测试应该被 "Is a for the life of the application" 取代。作为一名医生是一个人扮演的有时间限制的角色。这指向使用组合。这样,一个人一旦符合资格就可以成为医生,如果他们被取消资格,就可以恢复为一个人。在对象的生命周期中更改对象的具体类型从来都不是一个好主意。
如果我误解了您的问题,请提前致歉。
当Doctor对象存入内存后,就会进行分配 对于 superclass(Person)中的字段,然后是 Doctor class.
中的字段所以当医生对象存储在内存中时,它是一个完整的对象而不是 一半是人,一半是医生。
JVM 对象知道连接到 Doctor 对象内存分配的结构是 Doctor 对象的唯一方法是通过 标记为 "native pointer to class information."
的 4 字节数量类型安全转换和 instanceof 运算符等使用此信息来确定此内存分配属于哪个 class 结构 到.
所以是的,确实是继承关系,如前所述 回答因为医生是一个人(如果医生有病人那么它就是组合)
Bill Venners 的这篇文章对该主题进行了更详细的解释。 http://www.artima.com/designtechniques/initializationP.html
更重要的一点是,即使 Person 有私有变量,在 Doctor 中仍然无法直接访问,当内存分配给 Doctor 对象有分配给私有变量的内存 清楚地表明 super 和 sub class 的整个变量集 一起构成子class.