在重写方法内的匿名内部类中调用super方法

时间:2015-01-26 10:31:28

标签: java class

想象一下,我们有一个班级:

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.m();
}

目前我的解决方案是创建一个调用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()以及是否有其他方式来执行此任务。

3 个答案:

答案 0 :(得分:11)

  

我想知道为什么我无法写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();
}

答案 1 :(得分:4)

编写A.super.m(),假设A有一个带m方法的超类。 但是在你的代码中,你没有指定一个超类,默认情况下,你拥有的唯一超类是Object。 但是对象类没有一个&#39; m&#39;方法,所以你不能称之为。 做这样的事情的好方法是使用设计模式,比如装饰。

答案 2 :(得分: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()表达式。