Вызов супер метода изнутри анонимного внутреннего класса внутри переопределенного метода
Предположим, что мы имеем класс
class A {
public void m() {
System.out.println("A - > m()");
}
}
и я хочу переопределить метод m() при создании класса без, сделав второй подкласс B для расширения A.
public static void main(String[] args) {
A a = new A() {
@Override
public void m() {
System.out.println("Override - > m()");
new Thread(new Runnable() {
@Override
public void run() {
// I want to be able to call the super method.
// This is illegal!
A.super.m();
}
}).start();
}
};
a.method();
}
В настоящее время мое решение заключается в создании частного метода, который вызывает super.m()
A a = new A() {
private void superMethod() {
super.m();
}
@Override
public void m() {
System.out.println("Overrided - > m()");
new Thread(new Runnable() {
@Override
public void run() {
superMethod();
}
}).start();
}
};
a.m();
Я хочу знать, почему я не могу написать A.super.m() и есть ли другой способ выполнить эту задачу.
Ответы
Ответ 1
Я хочу знать, почему я не умею писать A.super.m()
...
Это потому, что A
на самом деле не является непосредственно окружающим классом. Прямо входящим классом Runnable
является new A() { ... }
, который является анонимным подклассом A
.
Другими словами, если бы вы имели
class A extends Base {
new Runnable() { ... }
}
тогда A.super
работал бы, но теперь у вас есть
class <Anonymous subclass of A> extends A {
new Runnable() { ... }
}
что означает, что что-то вроде A.super
невозможно, так как для <Anonymous subclass of A>.super.m
нет синтаксиса.
... и есть ли другой способ выполнить эту задачу.
То, как вы это решили, разумно, на мой взгляд. Другой способ - создать локальный подкласс A
(просто ввести идентификатор для использования в ____.super.m
) следующим образом:
public static void main(String[] args) {
class SubA extends A {
@Override
public void m() {
System.out.println("Override - > m()");
new Thread(new Runnable() {
@Override
public void run() {
SubA.super.m();
// ^^^^ we now have a name of the directly enclosing class
}
}).start();
}
}
A a = new SubA();
a.m();
}
Ответ 2
Написав A.super.m(), предположим, что A имеет суперкласс с методом m.
Но в вашем коде вы не указываете суперкласс, и по умолчанию единственный надкласс, который у вас есть, - Object.
Но класс Object не имеет метода "m", поэтому вы не можете его назвать.
Хороший способ сделать что-то подобное - использовать шаблон дизайна, например, декоратор.
Ответ 3
Я не думаю, что был бы более простой способ сделать это, кроме того, как у вас уже есть.
Проблема заключается в том, что анонимный класс A
(а не базовый класс A
) не может ссылаться внутри класса Runnable
. Анонимный класс представляется как нечто вроде package.A$1
при компиляции в собственный файл класса. Например, когда вы вызываете superMethod
внутри run
потока, выполняется следующий байт-код:
getfield mypackage/Test$1$1/this$1 Lmypackage/Test$1;
invokestatic mypackage/Test$1/access$0(Lmypackage/Test$1;)V
Чтобы ссылаться на свой базовый класс A
, ссылка на этот внутренний экземпляр класса отсутствует, поэтому вы вызываете выражение super.m()
.