无法在 Java 的匿名内部类中定义额外的方法

Posted

技术标签:

【中文标题】无法在 Java 的匿名内部类中定义额外的方法【英文标题】:Cannot define extra methods in an Anonymous Inner Class in Java 【发布时间】:2021-07-18 10:13:08 【问题描述】:

Anonymous Inner Class 中定义额外的方法(不覆盖超类方法)时,代码编译良好,没有任何问题,但是如果我尝试调用额外的方法,则会引发错误。那么当使用anonymous inner class 扩展时,是否只能在子类中使用override 方法?如果是这样,谁能解释一下为什么?

这是我的代码的样子

class SomeClass 

    public static void main(String[] args) 
        SomeOtherClass a = new SomeOtherClass() 

            @Override 
            public void methodFromSuperClass() 

                System.out.println("Method from super class!");
            

            public void subClassMethod() 
                System.out.println("Sub class method");
            

        ;

        a.methodFromSuperClass(); //This works fine

        a.subClassMethod(); // But calling this extra method throws an error
        
    

这是我遇到的错误

 SomeClass.java:20: error: cannot find symbol
      a.subClassMethod();
      ^
      symbol:   method subClassMethod()
      location: variable a of type SomeOtherClass
    1 error

【问题讨论】:

您的变量a 的类型为SomeOtherClass。似乎这种类型根本没有方法subClassMethod。所以编译器是正确的。添加公共成员没有多大意义,因为您无法访问它。 您可能想看看Official Java Doc on Anonymous Inner Classes。可以在你的类中添加方法,关键是它只能在类的范围内访问。 @Seelenvirtuose 很糟糕,我把它和Dynamic Method Dispatch 混淆了 【参考方案1】:

这种情况与匿名类一个名字完全一样:

class SomeOtherClass 
    public void methodFromSuperClass()  


class Subclass extends SomeOtherClass 
    @Override 
    public void methodFromSuperClass() 

        System.out.println("Method from super class!");
    

    public void subClassMethod() 
        System.out.println("Sub class method");
        

你做到了:

SomeOtherClass a = new Subclass();
a.subClassMethod();

你不同意你不能在这里打电话给subClassMethod吗?毕竟,编译器知道aSomeOtherClass 类型,但不知道它是SomeOtherClass 的哪个子类。它不会分析你的代码,看你实际上为它分配了一个Subclass 的实例。

匿名类的情况基本相同。只是这一次,子类在你的代码中没有名字,但它仍然是一个子类,同样的道理也适用于“编译器不会分析你的代码那么久” .

由于匿名子类没有名称,因此您不能像命名子类示例中那样执行 Subclass a = new Subclass(); 之类的操作,但从 Java 10 开始,您可以这样做:

var a = new SomeOtherClass()  ... ;

var 让编译器为您推断变量的类型,而无需您说出类型名称。编译器会将匿名子类推断为 a 的类型,这将允许您这样做:

a.subClassMethod();

最后,完全允许在匿名类中声明额外的成员——除了在匿名类内部或本地范围之外,很难从任何地方访问它们,因为匿名类没有名称。不过,有时声明额外成员仍然很有用,因为您可以在例如被覆盖的方法中访问它们。

【讨论】:

似乎我将它与Dynamic Method Dispatch 混淆了,因为在这种情况下,如果该方法在子类中被覆盖,那么即使变量在运行时为super 类型,子类的覆盖方法也是调用,那么这是否意味着编译器只对覆盖方法的代码进行更深入的分析? @ansme 不,重写的方法也在超类中声明,因此编译器可以看到调用methodFromSuperClass 是安全的,只需查看a 的类型,而不是您放入其中的实例。 a 的类型是一个常数,但是a 中的实例类型需要更多的分析,而且大部分时间不运行代码是不可能知道的。编译器也可以检查调用是否安全,让它在运行时崩溃,但Java不是这样设计的。另请参阅this。 非常感谢您的简短解释,现在更清楚了! :D【参考方案2】:

你的假设是正确的。不能以这种方式调用未覆盖的方法。 考虑一个例子,你声明了一个接口并用一个具体的类实例化了它,那么你仍然只能访问接口中定义的方法,而不能访问类中定义的方法。

public interface MyInterface
  public void someMethod();

public class MyImpl implements MyInterface
  //someMethod() implementation
  // ...
  // newMethod()
  public void newMethod()
    //some implementation
  

public class Main
  public static void main(String[] args)
    MyInterface inter = new MyImpl();
    inter.someMethod(); // this call is ok
    inter.newMethod();  // this call leads to a Symbol not found Exception, 
                        // because MyInterface has no method named newMethod...
  

希望现在更清楚这是什么意思

【讨论】:

以上是关于无法在 Java 的匿名内部类中定义额外的方法的主要内容,如果未能解决你的问题,请参考以下文章

Java匿名内部类的学习

请问JAVA中匿名内部类有啥用,举个例子,谢谢

Netty:在另一个方法中使用匿名内部类中定义的通道

java内部类之成员内部类之匿名内部类

Java中内部类详解—匿名内部类

请问JAVA中匿名内部类有啥用,举个例子,谢谢