有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我现在正在读Joshua Bloch的《有效的Java》,我很喜欢!但布洛赫在第112页(第24项)写道:

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

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


共 (5) 个答案

  1. # 1 楼答案

    但是,静态内部类没有对printMessage函数的访问权与它是内部类无关,而是它是静态的,不能调用非静态方法。我认为你提出的“静态”一词的使用在第一句中是含蓄的。他所指出的,或者他选择强调的,只是内部类仍然可以访问其父类的私有方法。他可能只是觉得在同一句话中进行静态/非静态的区分是不必要的或令人困惑的

  2. # 2 楼答案

    仅仅因为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
        }
    
    }
    
  3. # 3 楼答案

    你展示它的方式需要继承。但方法和字段可以通过以下方式进行访问:

    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!"); 
        }
    
      }
    }
    
  4. # 4 楼答案

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

    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;
        }
    }
    
  5. # 5 楼答案

    请注意错误消息。这并不是说你没有访问权限。它的意思是不能调用方法。实例方法在没有实例的情况下没有任何意义 打电话给他们。错误消息告诉您的是您没有该实例

    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总是关于访问。Bloch的观点是,内部类具有其他类不具有的访问权限。但是,任何访问权限都不允许您在不告诉编译器要在哪个实例上调用实例方法的情况下调用实例方法