【问题标题】:Can this code be considered for member overriding in Java?可以考虑将此代码用于 Java 中的成员覆盖吗?
【发布时间】:2021-03-02 12:37:45
【问题描述】:

理论上,Java 不支持成员覆盖,所以我在想这段代码 sn-p 是否可以用于覆盖类的成员。但是,我不太确定在什么情况下此代码可能会失败。我的意思是,如果这能完美运行,那么它就不会被忽视,对吧? 这可能是一个愚蠢的问题,但我真的很想知道这段代码在我无法想到的不同情况下会做什么。 因此,如果有人可以向我解释,那就太好了。 谢谢!

类A类{ 诠释 i = 10; 无效吃(){ System.out.println("在 A 类:吃"); } 无效树皮(){ System.out.println("在 A 类中:吠叫"); } } 类 ClassB 扩展 ClassA{ //int i = 20; 类B(){ 超级我 = 20; //改变A类中i的值。 } 无效吃(){ System.out.println("B 类:吃"); } } 公共类主{ 公共静态无效主要(字符串[]参数){ ClassB b = new ClassB(); System.out.println(b.i); 打(); b.树皮(); ClassA ua = new ClassB(); System.out.println(ua.i); ua.eat(); ua.bark(); ClassA a = new ClassA(); System.out.println(a.i); } }

【问题讨论】:

    标签: java oop object


    【解决方案1】:

    如果您覆盖一个方法然后尝试从父级调用它,父级调用派生方法,即使它在定义时不知道它。

    class A {
      public void foo() {
        System.out.println("A.foo");
      }
      public void callFoo() {
        this.foo();
      }
    }
    
    class B {
      public void foo() {
        System.out.println("B.foo");
      }
    }
    
    B instance = new B();
    instance.callFoo(); // Prints "B.foo"
    

    现在,如果我们尝试对实例字段做同样的事情,我们会得到原始字段。

    class A {
      public String foo = "A.foo";
      public void printFoo() {
        System.out.println(this.foo);
      }
    }
    
    class B {
      public String foo = "B.foo";
    }
    
    B instance = new B();
    instance.printFoo(); // Prints "A.foo"
    

    所以我们实际上并没有覆盖任何东西;我们只是简单地创建了一个新变量,它恰好与现有变量的名称混淆。如果它是真正的覆盖,那么我们将能够增强使用该变量但不知道子类的A 方法的行为。

    【讨论】:

    • 我想作者明白这一点。 Tejas 没有询问覆盖成员字段。
    【解决方案2】:

    您的问题的简单答案是“是”,您的 ClassA 类的 eat 方法在 ClassB 类中被覆盖。验证的简单选项是使用 @Override 注释。

    在子类中,您可以覆盖和重载实例方法。覆盖意味着,您是替换继承行为的子类。重载意味着,您正在扩展继承的方法。

    如果你修改你的ClassB如下,它会编译成功。

    class ClassB extends ClassA{
            //int i = 20;
            ClassB(){
                super.i = 20; //Changing the value of i in class A.
            }
            @Override  // **Added line is here** 
            void eat() {
                System.out.println("In Class B: Eating");
            }
    

    【讨论】:

      【解决方案3】:

      我不太确定这段代码在什么情况下可能会失败。

      它(有点)在人类读者/概念层面上失败了。

      Java 语言就是这样。这意味着 Java 程序员知道该期待什么,该做什么,不该做什么。

      继承的基本规则之一(在 java 中,但在一般情况下也是如此):对于超类的字段,您非常谨慎。成员字段应被视为类的内部实现细节。你不会把它暴露给外部世界。你不要把它暴露给你的孩子班级,除非有一个很好的理由这样做。如果您真的想在 java 中这样做,那么正确的方法是:为该字段使用 protected 关键字。

      您的想法基本上是子类“知道”超类字段,更糟糕的是:在创建时更改“内部状态”。

      因此,在现实世界中,这样的代码可能会很快导致各种令人讨厌的意外。因为现实世界中的不会期望子类会做类似的事情,因此在调试问题时,他们可能会惊讶地发现“我应该是 10,为什么是 20”大型应用程序。

      长话短说:你可以做某事并不意味着你应该去做。相反:好的编程是以“标准”方式做事,不会让你的读者感到惊讶。

      【讨论】:

      • +1。实现 OP 结果的一种标准的、不令人惊讶的方法是让 ClassA 具有类似 private final int i; public ClassA() { this.i = 10; } protected ClassA(int i) { this.i = i; } 的东西,这为其子类提供了一种清晰、明显、明确定义的方式来将 i 设置为需要。
      猜你喜欢
      • 2017-07-08
      • 2020-06-11
      • 1970-01-01
      • 1970-01-01
      • 2017-03-06
      • 1970-01-01
      • 2016-10-31
      • 1970-01-01
      • 2011-01-14
      相关资源
      最近更新 更多