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

2022-09-01 19:52:24

我目前正在阅读Joshua Bloch的《Effective Java》,我喜欢它!但在第112页(第24项),布洛赫写道:

静态成员类是最简单的嵌套类。最好将其视为一个普通类,它恰好在另一个类中声明,并且可以访问所有封闭类的成员,甚至是那些声明为私有的成员。

这真的让我感到困惑。我宁愿说:

静态成员类是最简单的嵌套类。最好将其视为一个普通类,它恰好在另一个类中声明,并且可以访问所有封闭类的静态成员,甚至是那些声明为私有的成员。

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

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 方法,因为它是在静态内部类中声明的,而 printMessage 方法是实例方法。看起来作者建议静态成员类可以访问封闭类的非静态字段。我确信我误解了他的最后一句话,但我不知道是什么。任何帮助将不胜感激!

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


答案 1

仅仅因为 is ,并不意味着它无法通过其他方式(通常作为参数)获取对 实例的引用,例如InnerClassstaticOuterClass

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
        }

    }
}

如果不是嵌套在里面,它就没有访问过这个方法。InnerClassOuterClassprivate

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
    }

}

答案 2

请注意错误消息。这并不是说您没有访问权限。它说不能调用该方法。实例方法没有任何意义,没有实例来调用它们。错误消息告诉您的是,您没有该实例。

Bloch 告诉你的是,如果该实例存在,则内部类中的代码可以调用其上的私有实例方法。

假设我们有以下类:

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

如果我们尝试从某个随机类调用这些私有方法,则无法:

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
  }
}

请注意,这些错误消息显示“专用访问”。

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

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

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

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
    }
  }
}

如果我们添加一个非静态的内部类,看起来我们可以做魔术:

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

但是,这里发生了一些诡计:一个非静态的内部类总是与外部类的实例相关联,你真正看到的是:

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

此处,是用于访问该外部实例的特殊语法。但是,只有当它不明确时,例如,如果外部类和内部类具有具有相同名称的方法,您才需要它。OuterClass.this

还要注意,非静态类仍然可以做静态类可以做的事情:

  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


推荐