有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如果方法名称相同,java如何使扩展类不从上面的类触发方法?

我的程序中有两个类有相同的方法,其中一个扩展了另一个

A

class A{

  public A(){
    this.sameMethod();
  }

  public void sameMethod(){
    System.out.println("This is A");
  }
}

扩展类A的类B

class B extends A{

  private int i;

  public B(int i){
    this.i = i;
    this.sameMethod();
  }

  public void sameMethod(){
    System.out.println("This is B");
    System.out.println("int value: " + i);
  }
}

C扩展类B

class C extends B{

  public C(int i){
    super(i);
  }
}

当我用参数int i = 1初始化类C时,我得到以下输出:

This is B
int value: null
This is B
int value: 1

为什么类A从类B调用sameMethod()? 如何在不更改方法名称的情况下解决此问题

如何获得此输出?:

This is A
This is B
int value: 1

共 (3) 个答案

  1. # 1 楼答案

    这就是被称为继承的面向对象编程(OOP)概念。父类定义特定的行为,子类可以更改其行为方式。当您在子类中定义具有相同签名的方法时,子类被称为覆盖了父类定义的行为

    当您在父类A中调用this.sameMethod()时,它将调用B中定义的sameMethod(),因为该方法已被redefined

    在你的例子中,看起来你需要你的孩子在父母的基础上做一些额外的事情

    class A{
    
      public A(){
        this.sameMethod();
      }
    
      public void sameMethod(){
        System.out.println("This is A");
      }
    }
    
    class B extends A{
    
      private int i;
    
      public B(int i){
        // Parent class has already called this, you don't do this here
        // this.sameMethod();
    
        this.i = i; // You really need this
      }
    
      public void sameMethod(){
        super.sameMethod(); // This means that the child class also does whatever its parent does
        System.out.println("This is B");
        System.out.println("int value: " + i);
      }
    }
    

    我想说,在不同级别的构造函数中调用sameMethod()通常是一个坏主意。如果基类(或父类)调用其构造函数中的特定方法,则存在一个隐式约定,即所有实例都需要执行一次来初始化某个对象。知道你的父母已经这样做了,而你也在尝试做类似的事情,当别人看你的代码时,很可能会引起混乱。如果它必须做一些额外的事情,显然更清楚的是要有另一个方法,子类也可以在其构造函数中调用它

    举个例子:

    class Diner {
        public Diner() {
            this.eatWithMouth();
        }
        public void eatWithMouth() {
            System.out.println("Ate something.");
        }
    }
    
    class ThirstyDiner extends Diner {
        public ThirstyDiner() {
            super();
            this.drinkWater();
        }
        public void drinkWater() {
            System.out.println("Drank something.");
        }
    }
    
    class ThirstyDiner extends Diner {
        public ThirstyDiner() {
            super();
            this.eatWithMouth();
        }
        public void eatWithMouth() {
            System.out.println("Drank something."); // You don't actually eat anything -> contract violation
        }
    }
    
    class SlowDiner extends Diner {
        public SlowDiner () {
            super();
        }
        public void eatWithMouth() {
            super.eatWithMouth();
            System.out.println("Took 10 hours."); // At least this is marginally related
        }
    }
    
  2. # 2 楼答案

    您的示例的主要问题是,您从非final类的构造函数调用了一个可重写的方法。这正是你所展示的问题所在

    操作顺序:

    • 新的C(1)
    • 输入C(int)
    • 超级(1)
    • 输入B(int)
    • 超级()
    • 初始化类A的实例变量
    • 输入一个()
    • 同样的方法()=>;因为动态绑定调用了B.sameMethod()
    • 输入B.sameMethod()
    • 访问未初始化的B.i(默认值为0;至少应为0)
    • 离开B.sameMethod()
    • 留下
    • 初始化B类的实例变量
    • 指派B.i

    如您所见,在A()中调用sameMethod()是一个非常糟糕的主意。 通常,应该只从构造函数调用private或final方法

  3. # 3 楼答案

    如果要防止B.sameMethod重写A.sameMethod(同时保持相同的名称),则可以简单地将方法设置为私有:

    class A {
    
        public A(int i) {
            this.sameMethod();
        }
    
        private void sameMethod() {
            System.out.println("This is A");
        }
    }
    

    B中也有同样的事情:

    class B extends A {
    
        private int i;
    
        public B(int i) {
            super(i);
            this.sameMethod();
        }
    
        private void sameMethod() {
            System.out.println("This is B");
            System.out.println("int value: " + i);
        }
    }
    

    这样A.sameMethod就不会被B继承,行为也将如您所料