为什么这个静态内部 class 不能在其外部 class 上调用非静态方法?

Why can’t this static inner class call a non-static method on its outer class?

我目前正在阅读 Joshua Bloch 的 Effective Java,我很喜欢!但是在第 112 页(第 24 项)Bloch 写道:

A static member class is the simplest kind of nested class. It is best thought of as an ordinary class that happens to be declared inside another class and has access to all of the enclosing class’s members, even those declared private.

这让我很困惑。我宁愿说:

A static member class is the simplest kind of nested class. It is best thought of as an ordinary class that happens to be declared inside another class and has access to all of the enclosing class’s static members, even those declared private.

这里有一个片段可以说明我对这句话的理解:

public class OuterClass {

    public void printMessage(String message) {
        System.out.println(message);
    }

    private static class InnerClass {

        public void sayHello() {
            printMessage("Hello world!"); //error: Cannot make a static reference to the non-static method printMessage(String)
        }

    }
}

您可以看到 InnerClass 的 sayHello 方法无法访问 OuterClass 的 printMessage 方法,因为它是在静态内部 class 中声明的,而 printMessage 方法是一个实例方法。看起来作者建议静态成员 class 可以访问封闭 class 的非静态字段。我确信我误解了他最后一句话中的某些内容,但我无法弄清楚是什么。任何帮助将不胜感激!

编辑:我改变了这两种方法的可见性,因为它与我的问题无关。我对静态成员感兴趣,而不是私有成员。

你的表现方式需要继承。但是可以通过这种方式访问​​方法和字段:

public class OuterClass {

  private void printMessage(String message) {
    System.out.println(message);
  }

  private static class InnerClass {

    private void sayHello() {
        OuterClass outer = new OuterClass();
        outer.printMessage("Hello world!"); 
    }

  }
}

但是,静态内部 class 无法访问 printMessage 函数与它是内部 class 无关,但它是静态的并且可以' 调用 non-static 方法。我认为您建议使用 "static" 这个词在第一句话中是隐含的。他所指出的,或者选择强调的,只是内部 class 仍然可以访问其父 class 的私有方法。他可能只是认为在同一个句子中区分 static/non-static 是不必要的或令人困惑的。

仅仅因为 InnerClassstatic,并不意味着它不能通过其他方式获得对 OuterClass 实例的引用,最常见的是作为参数,例如

public class OuterClass {

    private void printMessage(String message) {
        System.out.println(message);
    }

    private static class InnerClass {

        private void sayHello(OuterClass outer) {
            outer.printMessage("Hello world!"); // allowed
        }

    }
}

如果 InnerClass 没有嵌套在 OuterClass 中,它将无法访问 private 方法。

public class OuterClass {

    private void printMessage(String message) {
        System.out.println(message);
    }

}

class InnerClass {

    private void sayHello(OuterClass outer) {
        outer.printMessage("Hello world!"); // ERROR: The method printMessage(String) from the type OuterClass is not visible
    }

}

注意错误信息。这并不是说您没有权限。是说方法无法调用。实例方法没有实例就没有任何意义 打电话给他们。错误消息告诉您的是您没有该实例。

Bloch 告诉您的是,如果 该实例存在,内部 class 中的代码可以调用它的私有实例方法。

假设我们有以下 class:

public class OuterClass {
  public void publicInstanceMethod() {}
  public static void publicClassMethod() {}
  private void privateInstanceMethod() {}
  private static void privateClassMethod() {}
}

如果我们尝试从一些随机 class 中调用这些私有方法,我们不能:

class SomeOtherClass {
  void doTheThing() {
    OuterClass.publicClassMethod();
    OuterClass.privateClassMethod(); // Error: privateClassMethod() has private access in OuterClass
  }
  void doTheThingWithTheThing(OuterClass oc) {
    oc.publicInstanceMethod();
    oc.privateInstanceMethod();      // Error: privateInstanceMethod() has private access in OuterClass
  }
}

请注意,这些错误消息显示 private access

如果我们向 OuterClass 本身添加一个方法,我们可以调用这些方法:

public class OuterClass {
  // ...declarations etc.
  private void doAThing() {
    publicInstanceMethod();  // OK; same as this.publicInstanceMethod();
    privateInstanceMethod(); // OK; same as this.privateInstanceMethod();
    publicClassMethod();
    privateClassMethod();
  }
}

或者如果我们添加一个静态内部 class:

public class OuterClass {
  // ...declarations etc.
  private static class StaticInnerClass {
    private void doTheThingWithTheThing(OuterClass oc) {
      publicClassMethod();  // OK
      privateClassMethod(); // OK, because we're "inside"
      oc.publicInstanceMethod();  // OK, because we have an instance
      oc.privateInstanceMethod(); // OK, because we have an instance
      publicInstanceMethod();  // no instance -> Error: non-static method publicInstanceMethod() cannot be referenced from a static context
      privateInstanceMethod(); // no instance -> Error: java: non-static method privateInstanceMethod() cannot be referenced from a static context
    }
  }
}

如果我们添加一个non-static内部class,看起来我们可以施展魔法:

public class OuterClass {
  // ...declarations etc.
  private class NonStaticInnerClass {
    private void doTheThing() {
      publicClassMethod();     // OK
      privateClassMethod();    // OK
      publicInstanceMethod();  // OK
      privateInstanceMethod(); // OK
    }
  }
}

然而,这里有诡计:non-static 内部 class 总是 与外部 class 的实例,而您真正看到的是:

  private class NonStaticInnerClass {
    private void doTheThing() {
      publicClassMethod();     // OK
      privateClassMethod();    // OK
      OuterClass.this.publicInstanceMethod();  // still OK
      OuterClass.this.privateInstanceMethod(); // still OK
    }
  }

这里,OuterClass.this 是访问外部实例的特殊语法。但是你只需要它,如果它是模棱两可的,例如如果外部和内部 classes 有同名的方法。

还要注意,non-static class 仍然可以做静态的可以做的事情:

  private class NonStaticInnerClass {
    private void doTheThingWithTheThing(OuterClass oc) {
      // 'oc' does *not* have to be the same instance as 'OuterClass.this'
      oc.publicInstanceMethod();
      oc.privateInstanceMethod();
    }
  }

简而言之:publicprivate 总是关于 access。 Bloch 的观点是内部 classes 可以访问其他 classes 没有的。但是,如果不告诉编译器您要在哪个实例上调用它,就无法调用实例方法。

在我看来,文字是绝对正确的。静态成员 类 可以访问封闭 类 的私有成员(某种程度上)。让我举个例子:

public class OuterClass {
    String _name;
    int _age;
    public OuterClass(String name) {
        _name = name;
    }
    public static OuterClass CreateOuterClass(String name, int age) {
        OuterClass instance = new OuterClass(name);
        instance._age = age; // Notice that the private field "_age" of the enclosing class is visible/accessible inside this static method (as it would also be inside of a static member class).
        return instance;
    }
}