关于Java中面向对象编程(OOP)中的继承、多态和封装的基本概念
父类
import com.renting_house.HouseTool; import java.util.Scanner; /* 相关的业务层 */ public class HouseService { // 数组用来存储其输入的信息,先动态创建数组,不分配空间大小String[] arr;int count; // 用来统计房屋的空间大小的 // 变量值private boolean variabel;private String key;// 新增房源的相关信息private String name;private String phone;private String address;private double MonthlyRent;private String state; Scanner sc = new Scanner(System.in); public HouseService(String key) {this.setKey(key); } // set以及getpublic String getName() {return name;} public void setName(String name) {this.name = name;} public String getPhone() {return phone;} public void setPhone(String phone) {this.phone = phone;} public String getAddress() {return address;} public void setAddress(String address) {this.address = address;} public double getMonthlyRent() {return MonthlyRent;} public void setMonthlyRent(double monthlyRent) {MonthlyRent = monthlyRent;} public String getState() {return state;} public void setState(String state) {this.state = state;} public String getKey() {return key;} public void setKey(String key) {this.key = key;} public boolean getVariabel() {return variabel; // 布尔值的返回类型是true或者false。 固定的不可以进行赋值} public void setVariabel(boolean variabel) {this.variabel = variabel;} // 新增房源的方法public void AddHouse() {// 创建工具类对象HouseTool houseTool = new HouseTool(getKey()); int i = 0;System.out.println("请输入添加房屋的数量:");count = sc.nextInt();sc.nextLine();System.out.println("如果数量添加错误请输入 : n");key = sc.nextLine();if (key.equals("n")) {count = 0;System.out.println("请重新输入添加房屋的数量:");count = sc.nextInt();sc.nextLine();} key = null; do {arr = new String[count];System.out.println("------------------请输入你的选择--------------------");System.out.print("姓名:");name = sc.nextLine();System.out.print("电话:");phone = sc.nextLine();System.out.print("地址:");address = sc.nextLine();System.out.print("月租:");MonthlyRent = sc.nextDouble();sc.nextLine(); // 这是清楚掉nextInt();遗留的换行符System.out.print("状态:");state = sc.nextLine();System.out.println("------------------添加完成--------------------"); if (i < arr.length) {arr[i] = name + "\t" + phone + "\t" + address + "\t" + MonthlyRent + "\t" + state;} // 这里的接受有问题。没有接受到 。 不要在这里使用, // System.out.println(“是否要继续添加 : y/n”); // setKey(key = sc.nextLine()); // System.out.println(getKey()); houseTool.judgement(); } while (getVariabel()); for (String value : arr) {if (value == null) {System.out.println(" ");}System.out.println(value);}System.out.println("-----------------------------");System.out.println(getKey());System.out.println(getVariabel()); } public static void main(String[] args) {HouseService houseService = new HouseService("null");houseService.AddHouse();} }
子类
/* 工具类 */ public class HouseTool extends HouseService { public HouseTool(String key) {super(key); } // 用于添加出租屋中的逻辑判断 public void judgement() {System.out.println("是否要继续添加 : y/n");setKey(sc.nextLine());System.out.println(getKey()); do {if (getKey().equals("n")) {System.out.println(getKey());setVariabel(false);System.out.println(getVariabel());break;} if (getKey().equals("y")) {System.out.println(getKey());setVariabel(true);System.out.println(getVariabel());break; } else {System.out.println("未检测到有效的指令");System.out.println("是否要继续添加 : y/n");setKey(sc.nextLine());}} while (true); }
输出
true 子类是true x qe wsfc 100.0 zfc null null null null false 在父类中,为什么依旧是false
疑问
true 子类是true 但是 false 在父类中,为什么依旧是false
回答
-
尝试在
HouseService
类(即父类)中使用getVariabel()
时,会返回默认值(通常是false
或未初始化状态),因为在父类中并没有这样的方法或变量。如果想让父类也能够访问并修改这个布尔变量,需要在父类中也定义相应的 getter 和 setter 方法,或者将这个布尔变量设为protected
让子类可以访问,然后在judgement()
方法中直接通过父类引用来操作这个变量。
在父类中也定义相应的 getter 和 setter 方法
-
对象状态与实例变量: 在Java中,对象的状态是由其类中的实例变量(也称为字段)所决定的。当一个类继承自另一个类时,子类继承了父类的所有非私有(non-private)方法和变量(包括保护的protected和默认的包级别访问权限的变量)。但是,继承并不意味着子类对象与父类对象共享同一个实例变量;相反,每个对象实例都有自己的一套实例变量副本。
-
方法覆盖(Overriding)与实例变量: 在您的例子中,您并没有覆盖任何方法(除非
HouseService
类中有一些未在代码中显示的方法被您重写了)。但更重要的是,实例变量的值是由具体对象实例的状态所决定的,而不是由类的继承关系决定的。因此,无论您在子类还是在父类中访问一个实例变量,您都将得到与当前对象实例相关的值。 -
当前对象的实例相关值。这和很重要,这也是为什么,true 子类是true 但是 false 在父类中,为什么依旧是false。尽管继承了。但是在不同对象里面,等到的都是当前对象实例相关的值
更加准确的解释是
-
如果父类有一个实例变量,并且您在父类对象中将其设置为
false
,在子类对象中将其设置为true
(假设子类没有隐藏这个变量),那么这两个对象将分别拥有false
和true
的值,因为它们是两个完全不同的对象实例。重要的是要理解,即使子类继承了父类,子类对象中的实例变量值也不会影响父类对象中的实例变量值,因为它们是独立的对象实例。
-
一个更准确的表述可能是:“尽管子类继承了父类,但子类对象和父类对象中的实例变量值仍然是各自独立的,由各自对象实例的状态决定。
解决
-
正如上述表述
-
尽管子类继承了父类,但子类对象和父类对象中的实例变量值仍然是各自独立的,由各自对象实例的状态决定。
-
可以通过在父类中调用子类的相关函数。并且将其赋值给父类的变量
-
代码 :子类 。
public boolean judgement() { do {System.out.println("是否要继续添加 : y/n");setKey(key = scanner.nextLine());System.out.println(getKey()); // 这里我们实际上不需要一个 do-while 循环,因为只需要读取一次输入if ("n".equals(key)) {return false;} if ("y".equals(key)) {return true;} else {System.out.println("未检测到有效的指令");} }while (true);}
-
代码 :父类
do {arr = new String[count];System.out.println("------------------请输入你的选择--------------------");System.out.print("姓名:");name = scanner.nextLine();System.out.print("电话:");phone = scanner.nextLine();System.out.print("地址:");address = scanner.nextLine();System.out.print("月租:");MonthlyRent = scanner.nextDouble();scanner.nextLine(); // 这是清楚掉nextInt();遗留的换行符System.out.print("状态:");state = scanner.nextLine();System.out.println("------------------添加完成--------------------"); if (i < arr.length) {arr[i] = name + "\t" + phone + "\t" + address + "\t" + MonthlyRent + "\t" + state;} variabel = houseTool.judgement(); } while (variabel);
-
如上述代码的显示;父类中调用子类的相关函数。并且将其赋值给父类的一共变量。(这样就子类和父类的布尔值就是一样的)
-
注意:直接在父类中调用子类的方法通常不是一个好的设计,因为它违反了面向对象设计中的一个基本原则:封装和抽象。