it-swarm.com.de

Warum kann diese statische innere Klasse nicht eine nicht statische Methode für ihre äußere Klasse aufrufen?

Ich lese gerade Effective Java von Joshua Bloch und ich liebe es! Auf Seite 112 (Punkt 24) schreibt Bloch:

Eine statische Member-Klasse ist die einfachste verschachtelte Klasse. Es ist das beste gedacht als eine gewöhnliche Klasse, die zufällig in .__ deklariert wird. eine andere Klasse und hat Zugriff auf alle Mitglieder der umgebenden Klasse sogar die als privat erklärt.

Und das verwirrt mich wirklich. Ich würde eher sagen:

Eine statische Member-Klasse ist die einfachste verschachtelte Klasse. Es ist das beste gedacht als eine gewöhnliche Klasse, die zufällig in .__ deklariert wird. eine andere Klasse und hat Zugriff auf alle static mitglieder der Klasse, sogar die als privat erklärt.

Hier ist ein Ausschnitt, der mein Verständnis des Zitats veranschaulicht:

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

    }
}

Sie können sehen, dass die sayHello-Methode von InnerClass keinen Zugriff auf die printMessage-Methode von OuterClass hat, da sie in einer statischen inneren Klasse deklariert ist, während die printMessage-Methode eine Instanzmethode ist. Anscheinend schlägt der Autor vor, dass eine statische Member-Klasse auf nicht statische Felder der umgebenden Klasse zugreifen kann. Ich bin überzeugt, dass ich etwas in seinem letzten Satz falsch verstanden habe, aber ich kann nicht herausfinden, was. Jede Hilfe wird geschätzt!

edit: Ich habe die Sichtbarkeit der beiden Methoden geändert, weil sie für meine Frage irrelevant ist. Ich interessiere mich für statische Mitglieder, nicht für private Mitglieder.

21
Robin Dos Anjos

Nur weil InnerClassstatic ist, bedeutet dies nicht, dass es keinen Verweis auf eine Instanz von OuterClass auf andere Weise erhalten konnte, meist als Parameter, z.

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
        }

    }
}

Wenn InnerClass nicht in OuterClass geschachtelt worden wäre, hätte es keinen Zugriff auf die private-Methode.

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
    }

}
45
Andreas

Beachten Sie die Fehlermeldung. Es heißt nicht, dass Sie keinen Zugriff haben . Es heißt, dass die Methode nicht aufgerufen werden kann . Instanzmethoden bedeuten nichts ohne eine Instanz zum Aufruf von Die Fehlermeldung sagt Ihnen, dass Sie diese Instanz nicht haben.

Bloch sagt Ihnen, dass wenn diese Instanz existiert, Code in der inneren Klasse private Instanzmethoden für sie aufrufen kann.

Angenommen, wir haben folgende Klasse:

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

Wenn wir versuchen, diese privaten Methoden aus einer zufälligen Klasse aufzurufen, können wir nicht:

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

Beachten Sie, dass in diesen Fehlermeldungen private access steht.

Wenn wir OuterClass selbst eine Methode hinzufügen, können wir diese Methoden aufrufen:

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

Oder wenn wir eine statische innere Klasse hinzufügen:

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

Wenn wir eine nicht statische innere Klasse hinzufügen, können wir Magie ausführen:

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

Allerdings gibt es hier Trickereien: Eine nicht-statische innere Klasse ist always, die mit einer Instanz der äußeren Klasse verbunden ist.

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

Hier ist OuterClass.this eine spezielle Syntax für den Zugriff auf diese äußere Instanz. Sie brauchen es jedoch nur, wenn es mehrdeutig ist, z. wenn die äußere und innere Klasse Methoden mit demselben Namen haben.

Beachten Sie auch, dass die nicht statische Klasse weiterhin die Funktionen der statischen Klasse ausführen kann:

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

Kurz gesagt: public und private beziehen sich immer auf access . Der Punkt, den Bloch macht, ist, dass innere Klassen Zugriff haben, was andere Klassen nicht haben. Mit keinem Zugriff können Sie jedoch eine Instanzmethode aufrufen, ohne dem Compiler mitzuteilen, für welche Instanz Sie sie aufrufen möchten.

8
David Moles

Die Art, wie Sie es gezeigt haben, erfordert Vererbung. Auf Methoden und Felder kann jedoch auf folgende Weise zugegriffen werden:

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

  }
}
6
Ivan

Dass die statische innere Klasse jedoch keinen Zugriff auf die printMessage-Funktion hat, hat nicht damit zu tun, dass es sich um eine innere Klasse handelt, sondern dass sie statisch ist und keine nicht statische Methode aufrufen kann. Ich denke, die Verwendung des von Ihnen vorgeschlagenen Wortes "statisch" war im ersten Satz implizit. Was er darauf hinweist oder betont, ist nur, dass die innere Klasse immer noch auf private Methoden ihrer übergeordneten Klasse zugreifen kann. Es wäre vielleicht gerade unnötig oder verwirrend gewesen, die statische/nicht-statische Unterscheidung in demselben Satz zu treffen. 

4
Kris

So wie ich es sehe, ist der Text absolut richtig. Statische Member-Klassen können auf die privaten Member der umgebenden Klassen zugreifen (Art von). Lassen Sie mich ein Beispiel zeigen:

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