子类重写父类变量

当我们在父类和子类中创建一个具有相同名称的变量,并尝试使用持有子类对象的父类引用访问它时,我们会得到什么?

为了理解这一点,让我们考虑下面的示例,在该示例中,我们在ParentChild类中都声明了一个具有相同名称的变量x

class Parent {// Declaring instance variable by name `x`String x = "Parent`s Instance Variable";public void print() {System.out.println(x);}
}class Child extends Parent {// Hiding Parent class's variable `x` by defining a variable in child class with same name.String x = "Child`s Instance Variable";@Overridepublic void print() {System.out.print(x);// If we still want to access variable from super class, we do that by using `super.x`System.out.print(", " + super.x + "\n");}
}

现在,如果我们尝试使用以下代码访问x ,将打印什么System.out.println(parent.x)

Parent parent = new Child();
System.out.println(parent.x) // Output -- Parent`s Instance Variable

通常,我们会说Child类将覆盖Parent类中声明的变量,并且parent.x将给我们任何Child's对象所持有的东西。 因为在方法上进行相同类型的操作时发生的是同一件事。

但实际上并非如此, parent.x将为我们提供在Parent类中声明的Parent实例变量的值,但是为什么呢?

因为Java中的变量不遵循多态性,所以重写仅适用于方法,而不适用于变量。 并且,当子类中的实例变量与父类中的实例变量具有相同的名称时,则从引用类型中选择该实例变量。

在Java中,当我们在Child类中使用已经用于在Parent类中定义变量的名称定义变量时,Child类的变量将隐藏父类的变量,即使它们的类型不同。 这种概念称为可变隐藏。

换句话说,当子类和父类都具有相同名称的变量时,子类的变量将隐藏父类的变量。 您可以在文章什么是Java中的变量阴影和隐藏中阅读有关变量隐藏的更多信息。

变量隐藏与方法覆盖不同

尽管变量隐藏看起来像是覆盖变量,类似于方法覆盖,但事实并非如此,但覆盖仅适用于方法,而隐藏适用于变量。

方法覆盖的情况下,覆盖方法完全替换了继承的方法,因此当我们尝试通过持有子对象来从父对象的引用访问该方法时,将调用子类中的方法。 您可以在“方法重载与方法重载”一书中了解有关重载以及被重载的方法如何完全替代继承的方法的更多信息,以及为什么要遵循方法 重载 规则 。

但是在变量隐藏中,子类隐藏继承的变量而不是替换它们,这基本上意味着子类的对象包含两个变量,而子变量则隐藏了父变量。 因此,当我们尝试从Child类中访问变量时,将从子类中访问该变量。

如果我简化了示例8.3.1.1-3。 隐藏 Java语言规范 的实例变量 :

当我们在Child类中声明一个具有相同名称的变量时,例如x作为Parent类中的实例变量,则

  1. 子类的对象包含两个变量(一个是从Parent类继承的,另一个是在Child本身中声明的),但是子类变量隐藏了父类的变量。
  2. 由于声明xChild皮的定义xParent ,类的声明中Child ,简单名称x总是指到外地类中声明的Child 。 并且,如果Child类方法中的代码想要引用Parent类的变量x ,则可以将其作为super.x来完成。
  3. 如果我们尝试访问ParentChild类之外的变量,则从引用类型中选择实例变量。 因此,以下代码中的表达式parent2.x给出了属于父类的变量值,即使它持有Child的对象,但((Child) parent2).x可以从Child类访问该值,因为我们进行了相同的转换参考Child

为什么以这种方式设计可变隐藏

因此我们知道实例变量是从引用类型而不是实例类型中选择的,并且多态性不适用于变量,但是真正的问题是为什么? 为什么变量被设计为跟随隐藏而不是覆盖。

因为如果我们在子类中更改其类型,则变量覆盖可能会破坏从父级继承的方法。

我们知道每个子类都从其父类继承变量和方法(状态和行为)。 想象一下,如果Java允许变量覆盖,并且我们在子类中将变量的类型从int更改为Object 。 它将破坏使用该变量的任何方法,并且由于子代已从父代继承了这些方法,因此编译器将在child类中给出错误。

例如:

class Parent {int x;public int increment() {return ++x;}public int getX() {return x;}
}class Child extends Parent {Object x;// Child is inherting increment(), getX() from Parent and both methods returns an int // But in child class type of x is Object, so increment(), getX() will fail to compile.
}

如果Child.x覆盖Parent.xincrement()getX()工作? 在子类中,这些方法将尝试返回错误类型的字段的值!

如前所述,如果Java允许变量覆盖,则Child的变量不能替代Parent的变量,这将破坏Liskov替代性原则(LSP)。

为什么从引用类型而不是实例中选择实例变量

如JVM内部如何处理方法重载和覆盖中所述 ,在编译时,覆盖方法调用仅从引用类处理,但是所有覆盖的方法在运行时都使用vtable被覆盖方法替代,这种现象称为运行时多态性。

同样,在编译时也从引用类型处理变量访问,但是正如我们所讨论的那样,变量不遵循重写或运行时多态性,因此它们在运行时不会被子类变量替代,仍然引用引用类型。

一般来说,没有人会建议隐藏字段,因为这会使代码难以阅读并造成混乱。 如果我们始终坚持下去,这种混乱就不会出现。
创建POJO并通过声明为私有字段来封装我们的字段的一般准则,并根据需要提供getter / setter,以便在该类之外看不到变量,并且子类无法访问它们。

您可以在此Github存储库中找到完整的代码,请随时提供宝贵的反馈。

翻译自: https://www.javacodegeeks.com/2018/11/instance-variable-class-overridden-class.html

子类重写父类变量

子类重写父类变量_为什么在子类中不重写超类的实例变量相关推荐

  1. 我的文档目录环境变量_从.env文件中为NodeJS加载环境变量

    作者:Writer Staff 翻译:疯狂的技术宅 原文:https://coderrocketfuel.com/article/how-to-load-environment-variables-f ...

  2. 为什么在子类中不重写超类的实例变量

    当我们在父类和子类中创建一个具有相同名称的变量,并尝试使用持有子类对象的父类引用访问它时,我们会得到什么? 为了理解这一点,让我们考虑下面的示例,其中在Parent和Child类中声明一个具有相同名称 ...

  3. java重写父类方法_重写父类方法

    在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写.需要注意的是,在子类中重写的方法需要和父类被重写的方法具有相同的方法名.参数列表以及返 ...

  4. python 定义变量_第三章(第2节):变量和常量

    变量的概念基本上和初中代数的方程变量是一致的,只是在计算机程序中,变量不仅可以是数字,还可以是任意数据类型,比如我们上节课刚刚学过的基本数据类型或者我们后面要学的自定义数据类型. 所谓常量就是不能改变 ...

  5. python设置环境变量_小白Python进行中

    一.安装 安装包的下载 在官网进行下载,我选用Python3.8.0. Welcome to Python.org​www.python.org 安装 安装的时候可以借鉴该视频. Windows 10 ...

  6. python打印多个变量名_如何在Python中打印单个和多个变量?

    请考虑下面Python 2.x中的两个Python代码片段.# Code 1 print 1 # Output: 1# Code 2 print(1) # Output: 1 在Python 2.X中 ...

  7. linux中设置环境变量_如何在Linux中设置环境变量

    linux中设置环境变量 Wondering how to set environment variables in Linux? This is exactly what we'll be doin ...

  8. python画图将标题中有变量_如何在matplotlib中打印变量名作为标题

    在python中不可能轻松地获取变量的名称(请参见answer).对于在python中传递给函数的变量,有使用inspect.详细信息here和基于此answer的案例解决方案的复杂解决方案impor ...

  9. Category中实现了原始类实例变量的get方法导致的警告

    开发任务完成了,就把项目中的警告清理了一下,最后就剩下这一个警告了. 警告信息 ld: warning: instance method 'alertView' in category from /U ...

最新文章

  1. oracle同时更新多列数据,ORACLE 11G 表联合更新多列
  2. cvr存储服务器的优势,CVR存储设备的结构与优势分析
  3. (python的坑,坑的我头晕,下行循环写后根遍历)
  4. 冒泡排序java代码_数据结构与算法—冒泡排序(Java实现)
  5. RHEL(Red Hat Enterprise Linux)配置YUM源
  6. c 语言差错编码实验结果,C语言程序设计实验报告(四).doc11111111111111111.doc
  7. Redis 突然变慢了如何排查并解决?
  8. Excel 【小型成绩分析系统初稿】(功能及适应性有待完善)
  9. 虚幻引擎插件 - Maya LiveLink - 安装和使用
  10. windows补丁下载地址
  11. 使用scrapy刷博客访问量(傻瓜式)
  12. 谷歌浏览器好用的复制粘贴插件_好用到炸的谷歌chrome浏览器必备扩展插件(一)...
  13. 【密码学】Java课设-文件加密系统(适用于任何文件)
  14. 来扯点ionic3[3] 页面的生命周期事件,也就是凡间所说的钩子
  15. MySQL:索引原理
  16. 系统集成项目管理工程师考试-项目管理口诀
  17. TCPcopy使用示例
  18. bzoj 4398 福慧双修 题解
  19. int * arr 与 int arr[] 这两种定义数组方式的疑问
  20. PL/SQL 基础知识

热门文章

  1. HDU 2504 又见GCD
  2. 牛客网 【每日一题】6月8日 [SCOI2005]最大子矩阵
  3. 夯实基础项目工程之图论——Uncle Bogdan and Country Happiness,Graph Coloring,How Many Paths?,Array Differentiation
  4. CodeForces:1103(div1)1104(div2)
  5. P5081 Tweetuzki爱取球(期望)(线性求逆元)
  6. P4336-[SHOI2016]黑暗前的幻想乡【矩阵树定理,容斥】
  7. [2020.11.3NOIP模拟赛]选数字【容斥】
  8. jzoj4282-[NOIP2015模拟10.29B组]平方数游戏【构造】
  9. SpringCloud Greenwich(七)集成dubbo先启动消费者(check=false),然后启动提供者无法自动发现注册
  10. Sentinel(十四)之控制台