访问匿名对象的受保护方法与通过命名引用访问

Ale*_* R. 18 java

假设我有这个抽象类:

package test.one;

public abstract class One {
  
  protected abstract void whatever();

  public void run() {
    whatever();
  }
  
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

package test.two;

import test.one.One;

public class Three {

  public static void main(String[] args) {
    One one = new One() {
      @Override
      protected void whatever() {
        System.out.println("Do whatever..");
      }
    };
    one.whatever();
  }
}
Run Code Online (Sandbox Code Playgroud)

这段代码编译失败,这是预料之中的。

test/two/Three.java:14: error: whatever() has protected access in One
    one.whatever();
       ^
1 error
Run Code Online (Sandbox Code Playgroud)

下面的代码编译成功,这似乎令人惊讶:

test/two/Three.java:14: error: whatever() has protected access in One
    one.whatever();
       ^
1 error
Run Code Online (Sandbox Code Playgroud)

不同之处在于,在后一种情况下,我在没有命名引用的情况下访问该方法。为什么编译器允许这样的访问?

Jon*_*eet 20

不同之处在于,在后一种情况下,我在没有命名引用的情况下访问该方法。为什么编译器允许这样的访问?

不,区别在于,在后一种情况下,您访问的是匿名类上的方法,而不是类型的引用上的方法One

抛开受保护访问的奇怪之处不谈,只需创建一个具有公共方法的匿名类,您就可以很容易地看到差异:

class Test {
    public static void main(String[] args) {
        // This is fine...
        new Object() {
            public void method() {
                System.out.println("Called");
            }
        }.method();
        
        // This is not, because Object doesn't contain a method called "method".
        Object o = new Object() {
            public void method() {
                System.out.println("Called");
            }
        };
        o.method();        
    }
}
Run Code Online (Sandbox Code Playgroud)

正如注释中所述,获得相同效果的另一种方法是使用var,以便变量的编译时类型是匿名类。

即使匿名类中的私有成员也可以在包含范围内访问,就像它们是普通的嵌套类一样。

  • 另一种显示方式是 `var one = new One() { /*...*/ }; one.whatever();` 之所以有效,是因为 `one` 的类型是匿名类,而不是 `One`,并且(正如您所说)匿名类与包含类位于同一个包中。 (11认同)
  • @ScottMcPeak [否则,如果成员或构造函数被声明为私有,则当且仅当访问发生在包含成员或构造函数声明的顶级类(第 7.6 节)的主体内时才允许访问。](https: //docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.1) (7认同)
  • @Corrodias ‘protected’ 比默认可见性“更广泛”,而不是更窄。它允许从同一个包以及其他包中的子类进行访问。 (4认同)
  • @luk2302,不,他也可以访问私有成员,只要他在同一条语句中执行此操作即可。您可以通过声明一个私有方法并在语句结束之前访问它来尝试它,您将能够在您所在的包上独立地执行此操作。 (3认同)