【问题标题】:Confusing java code - related to static binding令人困惑的java代码 - 与静态绑定相关
【发布时间】:2016-06-29 18:21:24
【问题描述】:

有关此代码的某些内容让我感到困惑。第一个打印行是 1600。我知道这与静态类是 Car 而不是 Sportscar 有关。但是我们将对象创建为跑车,那么为什么体积字段不是 3500?谢谢。

 public class Car {
 public int volume;

 public Car() { this(1600); }
 public Car(int volume) { this.volume = volume; }
 public String toString() { return "Car:" + volume; }
 }



 public class SportsCar extends Car {
 public int volume;

 SportsCar() { this(3000); }
 SportsCar(int volume) { this.volume = volume; }
 public String toString() {return "SportsCar:"+volume;}
 }



 public class CarApplication {
 public static void main(String [] args) {
 Car car = new SportsCar(3500);

 System.out.println(car.volume);
 System.out.println(car.toString());
 System.out.println(car);
 }
 } 

【问题讨论】:

标签: java dynamic-binding static-binding


【解决方案1】:

首先,请注意,当您调用SportsCar 的构造函数时,Java 会自动调用其父类Car 的默认构造函数。这会将对象的父 Car 类的 volume 字段设置为 1600。

在 Java 中,字段没有多态性。因此,尽管 SportsCar 类中的 toString() 方法总是覆盖其父类 (Car) 的方法,但访问同名实例变量的规则略有不同。

如果您从SportsCar 类中访问volume,则将使用SportsCarvolume。从类本身外部(所以当您从CarApplication 调用时)访问哪个实例变量取决于相关对象的compile-time 类型。因为您将car 的类型声明为Car,所以使用父类Carvolume 值--因此打印1600。如果您改为将 car 声明为 SportsCar,则会打印 3500。

另一种选择是:

System.out.println(((SportsCar)car).toString()); 

这将输出 3500,因为 car 的类型已转换为 SportsCar.

【讨论】:

    【解决方案2】:

    所以这里的重点是,当您使用 car.volume 时,car 变量是 Car 类型,对象引用是 SportsCar 类型。

    由于这两个类都有同一个名为 volume 的元素,并且您试图通过父对象变量引用它,所以它返回 1600。

    如果您要进行类型转换然后检查音量,它将按照以下代码返回 3500:

    System.out.println(((SportsCar)car).volume);
    

    【讨论】:

      【解决方案3】:

      当你以这种方式声明某些东西时:

      ParentClass variable = new ChildClass(Args);
      

      ParentClass 中的方法和字段是您唯一可用的。它受到限制,因为您将类型声明为ParentClass。因为Car 的体积是 1600,并且对象仅限于 ParentClass 的方法和字段,所以它打印 1600。

      一个例子如下:

      假设我有一个 Apple 类和一个 Fruit 类:

      public class Fruit {
          private String type;
      
          public Fruit(String type) {
              this.type = type;
          }
      
          public String getType() {
              return type;
          }
      }
      

      还有苹果班:

      public class Apple extends Fruit {
           private String variant;
      
           public Apple(String variant) {
                System.out.println("I like " + variant + apples too!");
                super("Apple");
           }
      
           public String getVariant() {
                return variant;
           }
      }
      

      现在我像这样实例化:

      Fruit ap = new Apple("Fiji");
      

      我无权访问getVariant() 或 Apple 类中的任何方法,因为该类型属于父类,而不是 Apple。我可以做到getType(),但就是这样。

      在你的情况下:

      public class SportsCar extends Car {
          public int volume;
      
          SportsCar() {
              this(3000); 
          }
      
          SportsCar(int volume) { 
              this.volume = volume; 
          }
      
          public String toString() {
              return "SportsCar:"+volume;
          }
      }
      

      虽然SportsCar 有自己的构造函数并获取自己的卷,但父类Car 是实际类型,导致调用Car 构造函数,因此将volume 设置为1600。要指定@ 987654336@ 对象,这样做:

      SportsCar sc = new SportsCar(3500);
      System.out.print(sc.toString());
      

      这将打印出来:

      SportsCar:3500
      

      你也可以像这样对它进行类型转换:

      Car c = new SportsCar(1600);
      System.out.print(((SportsCar) c).toString());
      

      【讨论】:

      • 谢谢,我现在明白为什么要打印 Car 的音量了,但是我们什么时候将它设置为 1600?
      • @Bar 你在默认构造函数中设置它,我的就是一个例子:)
      【解决方案4】:

      Aman Chhabra 的答案是正确的。您创建了一个来自 Car“家族”的 SportCar 对象。而且您要打印的是 Car 的体积,而不是 SportCar 的体积。

      另一种方法是创建一个 SportsCar 对象而不是 Car。

      P.s:您应该始终将您的类属性设置为私有 :)

      【讨论】:

      • 如果您同意某人的观点,请点赞。不要发布答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多