当前位置: 首页 > 面试题库 >

为什么在子类对象中为超类变量存储或分配内存?

翟鹏
2023-03-14
问题内容

在以下代码中-

class Mammal {
  String name = "furry ";
  String makeNoise() { 
    return "generic noise";
 }
}

class Zebra extends Mammal {
    String name = "stripes ";
    String makeNoise() { 
        return "bray"; 
    }
}

public class ZooKeeper {
    public static void main(String[] args) { 
       new ZooKeeper().go();
   }

   void go() {
      Mammal m = new Zebra();
      System.out.println(m.name + m.makeNoise());

      Zebra z = new Zebra();
      System.out.println(z.name + z.makeNoise());
   }
}

如果在eclipse的调试窗口中看到,则两个对象(mz)都包含name变量(furrystripes)的两个值。

我确实知道在多态中,子类也可以使用超类的泛型方法。但是,即使在隐藏的情况下,为什么子类对象也存储超类变量的值。有什么用吗?


问题答案:

首先 :作为一般规则,如果类定义了子类可以访问的字段,则子类 不应 重新定义该字段。这真是个坏主意。首先,您所看到的是使 私有
字段正常工作。重新定义子类中的非私有字段要求受到伤害。(当然,如果Joe编写Mammal而Mary编写Zebra并且Joe在某个时候添加了一个字段,Mammal而该字段恰好与Mary所使用的字段冲突Zebra,则Mary对此无能为力。这是将所有字段设为私有的原因之一。)

但是,即使在隐藏的情况下,为什么子类对象也存储超类变量的值。

这里的关键是要记住,字段不是多态的,只是方法。因此,对象中 必须 有两个name字段(一个来自from Mammal,一个来自from
Zebra),因为使用A Mammal型引用的代码需要查看Mammal name,而使用ZebraA型引用的代码需要查看Zebra
name

这就是为什么您的代码显示“ Furry bray”,然后显示“ stripes bray”的原因。你可以通过获得“毛茸茸的叫声”
m,因为访问namem(一个Mammal-typed变量)访问Mammalname(不是多态),让您‘毛茸茸’。但是随后您makeNoise使用m并返回"bray"了方法,因为调用的方法是on
Zebra(多态的)方法。然后,您再次使用zZebra类型参考)进行操作,并看到“ stripes
bray”,因为z访问Zebra的是name,而不是Mammal

您可能遇到的下一个问题是:如果我们将makeNoise两个类都更改为:

String makeNoise() { 
    return this.name;
}

为什么要ZooKeeper编码

  Mammal m = new Zebra();
  System.out.println(m.name + m.makeNoise());

  Zebra z = new Zebra();
  System.out.println(z.name + z.makeNoise());

从给我们“毛茸茸条纹” mstripes stripesz

这是相同的原因,只是它的表示形式不同。从类型引用m.name访问,因此看到的(不是多态的)。调用
方法(多态),以及里面的,有型,即使我们把它称为从-typed
(等用途的)。在那里使用Zebra的事实以及在代码中键入内容的事实都是Java多态性的关键。name``Mammal``Mammal``name``m.makeNoise
Zebra
makeNoise``Zebra``makeNoise``this``Zebra``Mammal``m``this.name``Zebra``name``makeNoise``this``Zebra``Zebra

让我们更进一步:如果Zebra根本没有定义makeNoise怎么办?

class Mammal {
    String name = "furry ";
    String makeNoise() { 
        return this.name;
    }
}

class Zebra extends Mammal {
    String name = "stripes ";
}

现在,我们从中获得“毛茸茸” m和“条纹毛茸”
z。其原因与上述相同:引用的类型确定使用哪个字段,并且在Mammal代码(makeNoise)中this具有类型Mammal。因此,即使我们调用makeNoiseusing
z,由于Zebra没有makeNoise,也Mammal被称为,所以查找的引用name具有类型Mammal

有什么用吗?

这是 至关重要的
正常工作,特别是在私人领域的情况下类。Mammal代码不必担心子类会出现并重新定义其字段。您可能有一个10级深的类层次结构,每个类都定义了自己的name,这很好,每个级别的代码都可以使用name它定义的。



 类似资料:
  • 我在Java中读到了关于将超类变量类型化为子类的知识,反之亦然。请告诉我哪些是有效的? 动物是超级类,有猫和狗子类。

  • 我理解超类/子类之间的关系以及强制转换是如何工作的。但是,我的问题是,如果知道中间有一个类,你能把一个超类转换成一个特定的子类吗?例如,如果我有一个动物类对象包含一个BigDog对象,我可以将该对象强制转换为Dog吗?如果BigDog中有Dog中不存在的方法怎么办? 简而言之,你当然可以说超类对象是子类对象,但为什么你可以反转呢? 转念一想, Java在调用方法时检查的是:引用(DOG)是否有引用

  • 在我的应用程序中,我有一个单一的活动架构,我为每个片段定义了一个“视图”类。 这个“视图”类包含视图状态和视图操作,它们引用视图的数据和操作。 例如,我有一个“MainFragment.kt”和一个相关的“MainView.kt”文件,它是这样的: 然后导入“主状态”和“操作”,并在“主状态ragment.kt”及其“视图模型”类中使用。 正如您所见,“MainView”被定义为一个对象,因为我不

  • 问题内容: 请参阅下面的代码,其中的方法被覆盖,但变量没有被覆盖。为什么允许在子类中声明重复的变量? 问题答案: 为什么在子类方法中不覆盖超类的实例变量,请参见下面的代码… 因为实例变量不能在Java中覆盖。在Java中,只能重写方法。 当你声明一个与超类中现有字段同名的字段时,新字段将隐藏现有字段。超类中的现有字段仍存在于子类中,甚至可以使用…遵守常规的Java访问规则。 因为实例变量在Java

  • 问题内容: 代码: 问题: 为什么Java允许执行以上代码,而C ++不允许执行? 上面的代码是否创建了无数个对象?由于本身包含一个对象,而该对象又包含一个本身具有对象的对象,依此类推。 问题答案: 两种语言之间关于您的问题的主要区别是Java是具有引用语义的语言(原始类型除外),而C ++是具有值语义的语言,该值允许通过引用和指针进行引用语义。 在两种语言中看起来 相似的 语法具有完全不同的含义

  • 问题内容: 我有一些这样的代码。 超级班 子类 所以问题是我可以将超类的对象转换为子类吗?这个问题对我来说是正确的吗? 但它给Class Cast异常。 问题答案: 您可以将子类转换为超级类,反之亦然。如果“车辆”是“超级类”,而“汽车”是子类,则所有“汽车”(子代)都是“汽车”(“超级”),但并非所有“车辆”都是“汽车”。