Java与C++多态访问成员变量/方法 对比

在 Java 中,情况与 C++ 非常相似 ,但也存在一个关键的语法区别 (关键字不同)和一个根本的机制区别(访问权限)。

核心结论速查表

特性 C++ Java
现象名称 变量隐藏 (Hiding) 变量隐藏 (Hiding) / 遮蔽 (Shadowing)
内存情况 父类和子类各存一份,互不干扰 父类和子类各存一份,互不干扰
访问子类变量 obj.varptr->var obj.varthis.var
访问父类变量 obj.Parent::var super.var (关键区别!)
多态性 ❌ 无 (静态绑定,看引用类型) ❌ 无 (静态绑定,看引用类型)
能否通过父类引用访问子类变量? ❌ 不能 (编译报错) ❌ 不能 (编译报错)

1. 代码实战演示

假设我们有以下类结构:

java 复制代码
class Parent {
    int value = 100; // 父类变量
}

class Child extends Parent {
    int value = 200; // 子类变量 (隐藏了父类的 value)

    public void show() {
        // 1. 访问子类变量 (默认)
        System.out.println("Child value: " + this.value); // 输出 200
        System.out.println("Child value: " + value);      // 输出 200 (省略 this)

        // 2. 访问父类变量 (关键语法)
        System.out.println("Parent value: " + super.value); // 输出 100
    }
}

public class Main {
    public static void main(String[] args) {
        Child obj = new Child();
        Child cRef = obj;   // 子类引用
        Parent pRef = obj;  // 父类引用 (指向同一个对象)

        System.out.println("=== 1. 通过子类引用访问 ===");
        System.out.println("cRef.value: " + cRef.value); // 输出 200 (看引用类型 Child)

        System.out.println("\n=== 2. 通过父类引用访问 ===");
        System.out.println("pRef.value: " + pRef.value); // 输出 100 (看引用类型 Parent)
        
        // pRef.super.value; // ❌ 错误!外部代码不能使用 super 关键字
        // pRef.Child::value; // ❌ 错误!Java 没有 :: 语法
        
        // 如果非要通过父类引用访问子类变量,需要强制类型转换
        System.out.println("((Child)pRef).value: " + ((Child)pRef).value); // 输出 200
    }
}

2. 关键区别解析

A. 语法关键字:super vs ::

这是最直观的区别:

  • C++ :使用作用域解析运算符 ::
    • 写法:obj.Parent::valueptr->Parent::value
    • 逻辑:明确指定"我要 Parent 命名空间下的 value"。
  • Java :使用 super 关键字。
    • 写法:super.value
    • 限制:super 只能在子类的方法内部使用 。你不能在 Main 类或其他外部类中写 obj.super.value,这会编译报错。外部只能通过强制类型转换 ((Child)obj).value 来访问子类变量,或者根本无法直接访问被隐藏的父类变量(除非父类提供了 getter 方法)。
B. 访问权限的严格性
  • C++ :只要继承方式是 publicprotected,且成员变量不是 private,子类就可以通过 Parent::value 访问父类变量。
  • Java
    • 如果父类变量是 private:子类完全无法访问 ,连 super.value 都会报错。必须通过父类的 public/protected 方法(如 getValue())访问。
    • 如果父类变量是 default (包私有):只有当子类和父类在同一个包下时,才能访问。
    • 如果父类变量是 protectedpublic:可以通过 super.value 访问。
C. "多态"的缺失 (与 C++ 一致)

这一点 Java 和 C++ 完全一样成员变量没有多态性

  • 无论你实际创建的是 new Child() 还是 new Parent()
  • 编译器只看引用变量的声明类型
    • Parent p = new Child(); -> p.value 永远访问父类的那份数据 (100)。
    • Child c = new Child(); -> c.value 永远访问子类的那份数据 (200)。
  • 这与方法(Method)的重写(Override)完全不同,方法是根据实际对象类型动态绑定的。

3. 如何在外部访问被隐藏的父类变量?

在 Jav中,如果你在 main 方法里有一个 Parent 类型的引用指向 Child 对象,你想访问父类的那个 value

  1. 直接访问pRef.value -> 得到的就是父类的值 (100)。这通常就是你想要的。
  2. 如果你想访问子类的值 :需要强转 ((Child)pRef).value -> 得到 200。
  3. 如果你想在子类方法内部访问父类值 :使用 super.value

注意 :Java 不支持 像 C++ 那样在外部通过 obj.Parent::value 这种语法来"穿透"子类的遮挡去显式读取父类变量(虽然在这个特定场景下,用父类引用 pRef 直接读到的本来就是父类变量,所以通常不需要这种语法)。

总结

你的需求 C++ 写法 Java 写法
在子类方法内访问父类变量 Parent::value super.value
在外部通过对象访问父类变量 obj.Parent::value 无法直接写 (需用父类类型引用 parentRef.value)
在外部通过对象访问子类变量 obj.value (需子类指针) obj.value (需子类类型引用)
核心机制 静态绑定 (看引用类型) 静态绑定 (看引用类型)

一句话记住:

Java 中变量也是隐藏 而非重写,没有多态。在子类内部用 super.变量名 访问父类变量;在外部则完全取决于你手里拿的是父类引用 还是子类引用

拥有子类的引用或者指针,在c++中能通过作用域限定访问父类的变量,而java中只能访问子类变量

相关推荐
2301_821700532 小时前
C++编译期多态实现
开发语言·c++·算法
Andya_net2 小时前
Spring | @EventListener事件机制深度解析
java·后端·spring
奥地利落榜美术生灬2 小时前
c++ 锁相关(mutex 等)
开发语言·c++
xixihaha13242 小时前
C++与FPGA协同设计
开发语言·c++·算法
lang201509282 小时前
18 Byte Buddy 进阶指南:解锁 `@Pipe` 注解,实现灵活的方法转发
java·byte buddy
重庆小透明2 小时前
【java基础篇】详解BigDecimal
java·开发语言
ID_180079054732 小时前
模拟1688商品详情的Python API实现,返回符合风格的JSON数据
开发语言·python·json
小小怪7502 小时前
C++中的函数式编程
开发语言·c++·算法
金山几座2 小时前
C#学习记录-事件
开发语言·学习·c#