【问题标题】:Java: Calling function in "this" class rather than a subclass (analog to "super")Java:在“this”类而不是子类中调用函数(类似于“super”)
【发布时间】:2012-11-15 17:31:36
【问题描述】:

是否可以在 Java 中调用可覆盖的方法,使其始终执行“本地定义”的版本,而不是子类的覆盖版本? IE。 super 的类比是指这个类,而不是超类?

让我举一个代码示例,希望能清楚地说明我想要做什么:

class A {
    void foo() {
        System.out.println("Foo from A");
    }

    void bar() {
        foo();  // <-- This is the important line!
    }
}

class B extends A {
    @Override
    void foo() {
        System.out.println("Foo from B");
    }
}

如果我执行new B().bar(),它将调用A 中定义的bar() 方法,该方法调用foo() 以在B 中被覆盖以打印“Foo from B”。

有没有一种方法可以强制bar() 方法调用A 中定义的foo() 方法,而不是B?就像我可以在B 中使用super.foo() 来调用foo() 中定义的foo() 方法A?不幸的是,使用this.foo() 仍然调用子类的版本。即使像 ((A) this).foo()A.this.foo() 这样的东西也不起作用。

显然,我可以简单地在 A 中定义 foo() 的私有或最终版本,然后调用它。但我希望有一个解决方案,我所做的只是将上面代码示例中的“重要行”更改为调用 foo() 以使其打印“Foo from A”的不同方式,最好不要使用反射之类的技巧。

【问题讨论】:

  • 调用哪个foo()是由value(实例)的类型决定的,而不是由variable的类型决定的,我. e. A a = new B(); a.foo(); 打电话给B.foo()
  • 您似乎发现了继承的(许多)问题之一。你最好使用组合而不是继承,这将产生更容易阅读、理解和弄清楚它在做什么的代码。
  • @Guillaume 我很惊讶这并没有经常出现而无法解决。例如,我正在考虑像 OutputStream 这样的所有基类型类,它们通过将它们转发到 write(int b) 来提供回退方法实现,如 write(byte[] b)。如果两者都覆盖,则不能再使用 super 来使用回退。

标签: java inheritance


【解决方案1】:

您的对象B。它不是A!这是一个例子:

public class Apple {
    public void printColor() {
        System.out.println("I am red");
    }

    public void bar() {
       printColor();
    }
}

然后是子类:

public class GrannySmithApple extends Apple {
    public void printColor() {
        System.out.println("I am green");
    }
}

GrannySmithApples 是绿色的,一直都是(除非它们已经烂了,但那完全是另一罐香蕉)!一旦你有了GrannySmithApple,它就不再是Apple了,除非你可以用它做所有与普通Apple相同的事情(printColoreat 等)有意义吗?从普通的AppleGrannySmithApple 的转换之间没有改变的任何东西显然还是一样的。

【讨论】:

    【解决方案2】:

    您可以在被调用的 A 中拥有一个“内部”foo()

    class A {
        private void fooInternal() {
            System.out.println("Foo from A");
        }
    
        void foo() {
            fooInternal();
        }
    
        void bar() {
            fooInternal();
        }
    }
    
    class B extends A {
        @Override
        void foo() {
            System.out.println("Foo from B");
        }
    }
    

    new B().bar() 现在将打印“Foo from A”,而 new B().foo() 将打印“Foo from B”。

    【讨论】:

    • @Mik378 你能解释一下如果调用new B().bar(),将如何调用被覆盖的方法。
    • 那行得通。这就是我在问题最后一段开头的意思,它是一种可能但不是那么优雅的解决方案。
    • 你认为这里有什么作用?如果您从子类对象调用它,在子类中重写的 IS 方法仍然会被调用。你用这个构造什么都做不了
    【解决方案3】:

    要么让你的方法静态(baadddddd),要么改变你的设计。

    确实,为子类提供默认行为是没有意义的,它被定义为使自己适应相关的方法。

    由于您的 foo() 方法似乎有所不同,您可以实现这样的策略模式:

    interface BarProcess{
        void foo();
    }
    
    public class DefaultBarProcess implements BarProcess{
        void foo() {
           System.out.println("Foo from A");
        }
    }
    
    public class AnotherBarProcess implements BarProcess{
        void foo() {
           System.out.println("Foo from B");
        }
    }
    
    class A {
    
        private BarProcess barProcess;
    
        public A(Bar barProcess){
          this.barProcess = barProcess;
        }
    
        void bar() {
            barProcess.foo();
        }
    }
    
    class B extends A {  //deprecated! No need to exist
    
    }
    

    【讨论】:

      【解决方案4】:

      据我所知,B 对象总是会调用自己的 foo() 方法。话虽如此,B.foo() 可以定义为调用超类的foo() 方法。例如,您可以如下定义B

      class B extends A {
          @Override public void foo() {
              super.foo();
          }
      }
      

      这样做会让BA 调用foo。但是这样做会一直这样做。

      【讨论】:

      • 我很奇怪 Java 提供了“超级”,但没有类似“我”或“这里”或“本地”或“这个”或类似的东西......
      • 是的,但是“this”指的是这个对象,而不是这个类……所以如果对象是 B,这实际上会调用 B 上的一个方法(即使它是从 A 调用的)
      • @Markus 最好将继承想象成B 从字面上复制A 的所有方法。这样,当bar() 调用foo() 时,除非另有说明,否则它将引用自己的foo()
      【解决方案5】:

      有这个经验法则:

      In Inheritance the most specific version of the method for that class is called.
      

      - 因此,如果在 B 的实例上调用,则始终会调用 Class Bfoo() 方法。

      -如果您希望使用上述代码调用Class Afoo() 方法,那么您将需要super 关键字。

      例如:

      class B extends A {
          @Override
          void foo() {
      
             super.foo();
          }
      }
      

      【讨论】:

        【解决方案6】:

        foo() 总是调用new ... 语句中使用的类的实例方法。

        简而言之,我认为您的问题的答案是NO,这是做不到的。它会阻止你完全覆盖部分行为。

        class A {
        
        method1() {
        ...
        method2();
        ...
        }
        
        class B extends A {
        
        // You can override method2 here to change the behaviour of method1 
        // because it will call **your** version of method2
        // You **don't** have to override method1 to achieve that
        
        method2() {
        ...
        }
        
        }
        

        【讨论】:

          【解决方案7】:

          this 引用“这个对象”,而不是“这个类”。

          这意味着如果你有一个扩展A的对象B,当它执行超类A中提到this的方法时,它实际上将指向B的实例,所以将在B上执行方法。

          您可以将A 中的方法视为默认方法。如果该方法在您的实际对象 B 中被覆盖,那么它将总是被调用。

          我建议您更改您的设计并使用组合而不是继承:这将确保明确的关注点分离,并使您的代码更易于理解和测试.

          【讨论】:

            【解决方案8】:

            正如其他人所说,没有直接的方法可以做到这一点,但您可以考虑这种结构的变体:

              void bar() {
                ClassA self = new ClassA();
                self.foo();  // <-- This is the important line!
              }
            

            【讨论】:

            • 不幸的是,foo() 会失去对所有局部变量的访问权限。但是“self”将是用于这种情况的一个很好的关键字! :)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-01-22
            • 2011-08-25
            • 1970-01-01
            • 1970-01-01
            • 2012-08-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多