Как сделать так, чтобы расширенный класс не вызывал метод сверху класса, если имена методов совпадают? - PullRequest
0 голосов
/ 29 ноября 2018

У меня проблема с двумя классами в моей программе, которые имеют один и тот же метод, и один из них расширяет другой.

Класс A:

class A{

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

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

Класс Bкоторый расширяет класс A:

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);
  }
}

И когда я инициализирую класс C с параметром int i = 1,тогда я получаю этот вывод:

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

Почему класс A вызывает sameMethod() из класса B?Как решить эту проблему без изменения имени метода?

Как получить этот вывод?:

This is A
This is B
int value: 1

Ответы [ 3 ]

0 голосов
/ 29 ноября 2018

Это концепция объектно-ориентированного программирования (ООП), называемая наследованием.Родительский класс определяет конкретное поведение, а дочерний класс может изменить его поведение.Когда вы определяете метод с такой же сигнатурой в дочернем классе, говорят, что дочерний класс переопределяет поведение, определенное его родительским классом.

Когда вы вызываете this.sameMethod() вродительский класс A, он будет вызывать sameMethod(), определенный в B, потому что метод уже был 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
    }
}
0 голосов
/ 29 ноября 2018

Основная проблема в вашем примере заключается в том, что вы вызываете переопределяемый метод из конструктора неконечного класса.Это приводит именно к проблемам, которые вы показываете.

Последовательность операций:

  • new C (1);
  • введите C (int)
  • super (1);
  • введите B (int)
  • super ();
  • инициализируйте переменные экземпляра класса A
  • введите A ()
  • sameMethod ();=> из-за вызовов динамического связывания B.sameMethod ();
  • введите B.sameMethod ()
  • доступ к неинициализированному Bi (со значением по умолчанию 0; по крайней мере, это должно быть 0)
  • оставьте B.sameMethod ()
  • оставьте A ()
  • инициализируйте переменные экземпляра класса B
  • назначьте Bi
  • ...

Как видите, вызов sameMethod () в A () - действительно плохая идея.Обычно вы должны вызывать закрытые или конечные методы только из конструктора.

0 голосов
/ 29 ноября 2018

Если вы хотите запретить 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, и поведение будет таким, как вы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...