`

Java子类父类属性的覆盖

    博客分类:
  • Java
阅读更多
Java code
class ParentClass { public int i = 10; } public class SubClass extends ParentClass { public int i = 30; public static void main(String[] args) { ParentClass parentClass = new SubClass(); SubClass subClass = new SubClass(); System.out.println(parentClass.i + subClass.i); } } 控制台的输出结果是多少呢?2040?还是60?



变量,或者叫做类的属性,在继承的情况下,如果父类和子类存在同名的变量会出现什么情况呢?这就是这道题要考查的知识点——变量(属性)的覆盖。

这个问题虽然简单,但是情况却比较复杂。因为我们不仅要考虑变量、静态变量和常量三种情况,还要考虑private、friendly(即不加访问修饰符)、protected和public四种访问权限下对属性的不同影响。

我们先从普通变量说起。依照我们的惯例,先来看一段代码:

Java code
class ParentClass { private String privateField = "父类变量--private"; /* friendly */String friendlyField = "父类变量--friendly"; protected String protectedField = "父类变量--protected"; public String publicField = "父类变量--public"; // private的变量无法直接访问,因此我们给他增加了一个访问方法 public String getPrivateFieldValue() { return privateField; } } public class SubClass extends ParentClass { private String privateField = "子类变量--private"; /* friendly */String friendlyField = "子类变量--friendly"; protected String protectedField = "子类变量--protected"; public String publicField = "子类变量--public"; // private的变量无法直接访问,因此我们给他增加了一个访问方法 public String getPrivateFieldValue() { return privateField; } public static void main(String[] args) { // 为了便于查阅,我们统一按照private、friendly、protected、public的顺序 // 输出下列三种情况中变量的值 // ParentClass类型,ParentClass对象 ParentClass parentClass = new ParentClass(); System.out.println("ParentClass parentClass = new ParentClass();"); System.out.println(parentClass.getPrivateFieldValue()); System.out.println(parentClass.friendlyField); System.out.println(parentClass.protectedField); System.out.println(parentClass.publicField); System.out.println(); // ParentClass类型,SubClass对象 ParentClass subClass = new SubClass(); System.out.println("ParentClass subClass = new SubClass();"); System.out.println(subClass.getPrivateFieldValue()); System.out.println(subClass.friendlyField); System.out.println(subClass.protectedField); System.out.println(subClass.publicField); System.out.println(); // SubClass类型,SubClass对象 SubClass subClazz = new SubClass(); System.out.println("SubClass subClazz = new SubClass();"); System.out.println(subClazz.getPrivateFieldValue()); System.out.println(subClazz.friendlyField); System.out.println(subClazz.protectedField); System.out.println(subClazz.publicField); } } 这段代码的运行结果如下: ParentClass parentClass = new ParentClass(); 父类变量--private 父类变量--friendly 父类变量--protected 父类变量--public ParentClass subClass = new SubClass(); 子类变量--private 父类变量--friendly 父类变量--protected 父类变量--public SubClass subClazz = new SubClass(); 子类变量--private 子类变量--friendly 子类变量--protected 子类变量--public


从上面的结果中可以看出,private的变量与其它三种访问权限变量的不同,这是由于方法的重写(override)而引起的。关于重写知识的回顾留给以后的章节,这里我们来看一下其它三种访问权限下变量的覆盖情况。

分析上面的输出结果就会发现,变量的值取决于我们定义的变量的类型,而不是创建的对象的类型。

在上面的例子中,同名的变量访问权限也是相同的,那么对于名称相同但是访问权限不同的变量,情况又会怎样呢?事实胜于雄辩,我们继续来做测试。由于private变量的特殊性,在接下来的实验中我们都把它排除在外,不予考虑。

由于上面的例子已经说明了,当变量类型是父类(ParentClass)时,不管我们创建的对象是父类(ParentClass)的还是子类(SubClass)的,都不存在属性覆盖的问题,因此接下来我们也只考虑变量类型和创建对象都是子类(SubClass)的情况。

Java code
class ParentClass { /* friendly */String field = "父类变量"; } public class SubClass extends ParentClass { protected String field = "子类变量"; public static void main(String[] args) { SubClass subClass = new SubClass(); System.out.println(subClass.field); } } 运行结果: 子类变量 Java代码 class ParentClass { public String field = "父类变量"; } public class SubClass extends ParentClass { protected String field = "子类变量"; public static void main(String[] args) { SubClass subClass = new SubClass(); System.out.println(subClass.field); } } 运行结果: 子类变量



上面两段不同的代码,输出结果确是相同的。事实上,我们可以将父类和子类属性前的访问修饰符在friendly、protected和public之间任意切换,得到的结果都是相同的。也就是说访问修饰符并不影响属性的覆盖,关于这一点大家可以自行编写测试代码验证。

对于静态变量和常量又会怎样呢?我们继续来看:

Java code
class ParentClass { public static String staticField = "父类静态变量"; public final String finalField = "父类常量"; public static final String staticFinalField = "父类静态常量"; } public class SubClass extends ParentClass { public static String staticField = "子类静态变量"; public final String finalField = "子类常量"; public static final String staticFinalField = "子类静态常量"; public static void main(String[] args) { SubClass subClass = new SubClass(); System.out.println(SubClass.staticField); System.out.println(subClass.finalField); System.out.println(SubClass.staticFinalField); } } 运行结果如下: 子类静态变量 子类常量 子类静态常量



虽然上面的结果中包含“子类静态变量”和“子类静态常量”,但这并不表示父类的“静态变量”和“静态常量”可以被子类覆盖,因为它们都是属于类,而不属于对象。

上面的例子中,我们一直用对象来对变量(属性)的覆盖做测试,如果是基本类型的变量,结果是否会相同呢?答案是肯定的,这里我们就不再一一举例说明了。

最后,我们来做个总结。通过以上测试,可以得出一下结论:

由于private变量受访问权限的限制,它不能被覆盖。
属性的值取父类还是子类并不取决于我们创建对象的类型,而是取决于我们定义的变量的类型。
friendly、protected和public修饰符并不影响属性的覆盖。
静态变量和静态常量属于类,不属于对象,因此它们不能被覆盖。
常量可以被覆盖。
对于基本类型和对象,它们适用同样的覆盖规律。

最后我们再回到篇首的那道题,我想答案大家都已经知道了,结果是40。

分享到:
评论

相关推荐

    java 子类对象赋值给父类对象的使用

    1. **方法覆盖**:当子类继承父类并重写父类中的方法时,通过父类引用调用该方法,将执行子类中的版本。这是多态性的一种体现。 2. **构造器与初始化**:子类对象在创建时会先调用父类的构造器,确保父类的状态得到...

    在父类获取子类属性

    1. **代码重用**:子类可以直接使用或覆盖父类的方法和属性,减少重复代码。 2. **多态性**:子类实例可以被视为父类类型,允许更灵活的设计和操作。 **访问子类属性:** 1. **直接访问**:如果子类的属性是public...

    java中的继承(子类调用父类构造方法还不懂).doc

    - **访问父类属性**:可以在子类中使用`super`关键字来访问父类的属性。 - **调用父类方法**:`super`也可以用来调用父类中的方法。 - **调用父类构造器**:最重要的是,`super`可以用于在子类构造器中调用父类的...

    论JAVA继承机制中父类与子类的关系

    protected String className = "父类属性"; public void print() { System.out.println("父类方法"); } } public class SubClass extends SuperClass { protected String className = "子类属性"; @Override ...

    JAVA 子类继承父类的范例 可直接运行

    在Java中,继承是面向对象编程的核心特征之一,它允许我们创建一个新类(子类)基于一个已经存在的类(父类或超类)的结构。这样可以复用现有类的代码,并可添加或覆盖特性来形成新的类。本文将通过具体的代码范例,...

    Java编程关于子类重写父类方法问题的理解

    由于子类重写了父类的overRide()方法,虽然per为父类对象引用,此时父类的该方法被覆盖,所以此时要调用子类的方法;执行过程同上,per不再指向以C为首地址的子类对象,改为指向新创建的子类对象,以D为首地址。 同...

    子类调用抽象父类.zip

    在子类中,除了重写父类的抽象方法外,子类还可以定义自己的属性,或者覆盖父类的非final属性。这允许子类根据自身的需求定制行为和状态。子类可以通过`super`关键字调用父类的构造函数,确保初始化时父类的属性得到...

    Java父类继承代码示例

    // 父类属性和方法 } public class Dog extends Animal { // 子类特有的属性和方法 } ``` 在这个例子中,`Dog`类继承了`Animal`类的所有非私有(public或protected)属性和方法。这意味着`Dog`类可以直接访问`...

    Java、C++中子类对父类函数覆盖的可访问性缩小的区别介绍

    Java 和 C++ 在子类覆盖父类函数时的可访问性缩小有显著的不同。首先,我们要理解什么是函数覆盖。在面向对象编程中,子类可以重写或覆盖父类的方法,以便实现自己的行为。在 Java 和 C++ 中,这个过程通常是通过...

    再次详细说明在继承中的程序执行顺序,子类与父类到底哪个先执行

    它允许子类从父类中继承属性和方法,从而实现代码的重用和扩展。本文将深入探讨在继承中的程序执行顺序,以及子类与父类的执行顺序问题。 首先,我们需要了解Java或Python等面向对象语言中类的构造过程。当一个类...

    继承的小例子

    在Java编程语言中,继承是面向对象编程的一个核心特性,它允许一个类(子类)继承另一个类(父类)的属性和方法。这个概念在软件工程中扮演着至关重要的角色,因为它促进了代码的重用、扩展和组织。标题"继承的小...

    父类引用指向子类对象

    父类定义了一组通用的属性和行为,而子类继承了这些属性和行为,并可能添加新的或覆盖已有的特性。例如,`Animal`可以作为所有动物的父类,而`Dog`和`Cat`则分别是`Animal`的子类。 当我们声明一个父类类型的引用,...

    关于JAVA继承的讲解

    Java 继承是面向对象编程中的一个重要概念,它允许一个类(子类)从另一个类(父类)中继承属性和方法,从而实现代码的复用和类的层次结构。这种方式使得子类能够继承父类的特性,同时可以添加自己的特性和功能,而...

    Java 实现继承实例代码

    这种设计模式有助于代码重用,使得子类可以继承父类的属性和方法,并且可以添加新的功能或覆盖已有的行为。本实例将通过`Tryextend.java`文件展示如何在Java中实现继承。 首先,让我们理解继承的基本语法。在Java中...

    PHP面向对象程序设计子类扩展父类(子类重新载入父类)操作详解

    如果在子类中定义了与父类同名的属性或方法,那么子类中的定义将会覆盖父类的定义,这就是所谓的“重写”。 关于方法的重写,PHP允许子类覆盖父类的方法,但需要注意的是,子类中重写的方法访问权限不能低于父类被...

    Java 中方法的重载与覆盖

    4. **如果父类中的方法是私有的(private)**:那么子类无法覆盖该方法,因为子类无法访问父类中的私有方法。 5. **访问权限不得降低**:如果父类中的方法具有public或protected访问权限,那么子类中的覆盖方法至少应...

    java中子类继承父类,程序运行顺序的深入分析

    在Java编程语言中,子类继承父类是一种常见的面向对象特性,它允许子类获取父类的属性和方法,并且可以进行扩展或覆盖。本文将深入分析Java中子类继承父类时的程序运行顺序,这对于理解面向对象编程的执行机制至关...

    java中带super关键字的程序内存分析

    7. **内存分配与垃圾回收**:在Java的内存模型中,父类的属性会在子类对象的内存空间中分配,这意味着父类的实例变量是子类对象的一部分。当子类对象被垃圾回收时,其包含的父类部分也会一同被回收。 综上所述,`...

    java学习笔记 继承 重载 覆盖

    继承允许子类继承父类的属性和方法,增强了代码的复用性。多态是指一个父类引用可以指向不同子类的实例,调用子类覆盖父类的方法。这样可以减少类间的耦合,使程序更具扩展性。 方法的重载(Overloading)是指在同...

Global site tag (gtag.js) - Google Analytics