Имея следующий суперкласс:
public class SuperClass {
protected Integer a;
protected Integer b;
public void doSomething() {
this.a = 10;
}
public void doEverything() {
SuperClass.this.doSomething();
this.b = 20;
}
public static void main(String[] args) {
SuperClass instance = new SubClass();
instance.doEverything();
System.out.println(instance.a); //should print 10
System.out.println(instance.b);
}
}
И следующий подкласс:
public class SubClass extends SuperClass {
@Override
public void doSomething() {
super.doSomething();
super.a *= 10;
}
public void doEverything() {
super.doEverything();
this.b += 5;
}
}
Выходы:
100
25
Итак, SuperClass.this.doSomething();
является доступ к SubClass
doSomething
, но мне нужно, чтобы получить доступ к SuperClass
doSomething
. В этом случае у меня нет ключевого слова super
, потому что я уже супер!
Есть ли способ SuperClass.this.doSomething
на глубокий SuperClass.this.doSomething
, поэтому он будет выводить 10
для первого выходного значения?
¹ Меня интересуют ссылки: мы могли бы, конечно же, извлечь SuperClass
doSomething
в личный метод auxiliar и получить к нему доступ напрямую.
Если нет способа, то может ли ситуация, когда метод суперкласса для доступа к другому (хотя и переопределенному) методу означает, что мой проект ООП неверен? Зачем?
Я предполагаю, что вы пришли на Java с фона C++. Языки похожи в понятиях и синтаксисе, но они различны в реализации.
Вы можете достичь того, что, на ваш взгляд, тоже есть на Java, но структура будет выглядеть иначе, чем C++.
В Java конструкция SuperClass.this
в вашем примере точно такая же, как и this
, поэтому SuperClass.this.doSomething();
это именно то, что может сделать doSomething()
. Итак, почему Java вообще имеет конструкцию SuperClass.this
? Он имеет значение, не связанное с наследованием. Это полезно в контексте вложенных классов.
Представьте себе такую структуру:
class A {
class B {
public void doSomething() {
// this here refers to an instance of the class B
System.out.println(this);
// We need to write is this way,
// because this hides the this reference to the instance of A.
// A.this is the instance of A where this is nested
System.out.println(A.this);
}
}
Итак, как вы можете быть уверены, что сможете иметь метод в классе, который подклассы могут переопределять и все еще иметь возможность вызвать конкретную реализацию?
Ну, в строгом смысле, вы не можете. То, что вы можете сделать, - это создать final
метод, который нельзя переопределить, и вызывать его из неконфигурированного метода.
class SuperClass {
public void doSomething() {
doSuperClassyThing();
}
public final void doSuperClassyThing() { // cannot be overridden
...
}
}
Аналогичный подход (с немного другой целью) вы можете увидеть в шаблоне метода шаблона.
Вы не можете делать то, что хотите. Способ полиморфизма работает, делая то, что вы видите.
Это означает, что нет прямого способа вызвать SuperClass.doSomething() из SuperClass.doSomething(), не перейдя в SubClass.doSomething(), если вы не работаете с фактическим экземпляром SuperClass.
На некоторых других языках вы можете рассказать, как обрабатывать это, например, с помощью ключевого слова virtual в c++, но в java у вас нет этой опции. Все методы динамически привязаны, поэтому вы не можете этого сделать. Вы не можете переопределить или вообще не переопределить его.
Ответ заключается в том, что вы не можете ссылаться на него. Единственный способ сделать это - это подход частного вспомогательного метода, о котором вы уже знаете.
Если вы хотите узнать причину, почему, я думаю, это просто потому, что это затруднит язык без причины; вы всегда можете получить тот же результат с помощью частного вспомогательного метода. Синтаксис SuperClass.this.doSomething()
уже сделан для чего-то другого. Это означает вызов метода doSomething
на охватывающем экземпляре, если SuperClass
является закрывающим классом.
Если вы когда-нибудь окажетесь в этой ситуации, возможно, вам следует переосмыслить и подумать, что структура классов еще не верна.
Попробуйте реализовать один из следующих подходов:
super
). Поскольку (1.) не было бы таким же сухим, как другие, (4.) оставляет ощущение обходного пути, и (2.) потребует создания нового файла и будет ссылаться на внешний SuperClass
; Я думаю, что самым близким подходом было бы (3.), что является единственным решением, которое каким-то образом ссылается на super
в SuperClass
(хотя на самом деле оно ссылается на внутренний класс SuperClass
):
SuperClass.java:
public abstract class SuperClass {
protected Integer a;
protected Integer b;
public void doSomething() {
this.a = 10;
}
public abstract void doEverything();
public static class Impl extends SuperClass {
@Override
public void doEverything() {
super.doSomething();
this.b = 20;
}
}
public static void main(String[] args) {
SuperClass instance = new SubClass();
instance.doEverything();
System.out.println(instance.a); //prints 10
System.out.println(instance.b);
}
}
SubClass.java:
public class SubClass extends SuperClass.Impl {
@Override
public void doSomething() {
super.doSomething();
super.a *= 10;
}
@Override
public void doEverything() {
super.doEverything();
this.b += 5;
}
}