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

时间:2018-04-10 20:43:36

标签: java class static member

我正在阅读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方法是一个实例方法。看起来作者似乎建议静态成员类可以访问封闭类的非静态字段。我确信我在他的最后一句话中误解了一些内容,但我无法弄清楚是什么。任何帮助将不胜感激!

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

5 个答案:

答案 0 :(得分:45)

仅仅因为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
    }

}

答案 1 :(得分:8)

请注意错误消息。它并没有说你无法访问。它说方法不能被称为。实例方法并不意味着没有实例的任何东西 打电话给他们。错误消息告诉您的是您没有该实例。

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

假设我们有以下课程:

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

然而,这里有一些技巧:非静态内部类总是与外部类的实例相关联,以及你&# 39;真正关注的是:

  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的观点是,内部课程可以访问其他课程。但是,没有任何访问权限允许您调用实例方法而不告诉编译器您想要调用它的实例。

答案 2 :(得分:6)

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

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!"); 
    }

  }
}

答案 3 :(得分:4)

但是,静态内部类无法访问printMessage函数并不意味着它是一个内部类,但它是静态的,不能调用非静态方法。我认为你提出的“静态”一词的使用隐含在第一句中。他指出或者选择强调的只是内部类仍然可以访问其父类的私有方法。他可能只是在同一个句子中进行静态/非静态区分是不必要的或混乱的。

答案 4 :(得分:0)

我看到的方式,文字是完全正确的。静态成员类可以访问封闭类的私有成员(排序)。让我举个例子:

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