Warum kann die innere Klasse die private final-Methode überschreiben?

Lesezeit: 5 Minuten

Benutzer-Avatar
chicout

Ich habe mich gefragt, ob es sinnvoll ist, eine private Methode auch als final zu deklarieren, und ich dachte, es macht keinen Sinn. Aber ich stellte mir vor, dass es eine exklusive Situation gibt, und schrieb den Code, um es herauszufinden:

public class Boom {

    private void touchMe() {
        System.out.println("super::I am not overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub::You suck! I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();
        inner.touchMe();
    }
}

Es hat kompiliert und funktioniert. “Ich sollte touchMe() final machen” dachte ich und tat es:

public class Boom {

    private final void touchMe() {
        System.out.println("super::I am not overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub::You suck! I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();
        inner.touchMe();
    }
}

und es funktioniert auch und sagt mir

chicout@chicout-linlap:~$ java Boom
super::I am not overridable!
sub::You suck! I overrided you!

warum?

  • Es ist “verstecken” oder “beschatten” oder so etwas. Zeigt irgendwie, warum das Erweitern der äußeren Klasse ein bisschen böse ist (sogar in Aufzählungen, wirklich). / Versuchen Boom inner = boom.new Inner();

    – Tom Hawtin – Angelleine

    1. März 2012 um 21:05 Uhr


  • Gutes Beispiel dafür, warum Sie die Annotation @Override verwenden sollten. Stellen Sie sicher, dass Sie die Methode tatsächlich überschreiben

    – Shawn

    1. März 2012 um 21:06 Uhr

  • Sollte es nicht schreiben super... zweimal? Aktualisieren Nein. Mea culpa. Aha.

    – Der Mike

    1. März 2012 um 21:08 Uhr


  • Die hier gegebenen Erklärungen lassen zu wünschen übrig. Die meisten von ihnen geben an, dass die Methode der inneren Klasse eine “getrennte Methode” von der Methode in der enthaltenden Klasse ist, eine Methode, die zufällig den gleichen Namen hat. (Dasselbe Unterschrift, möchte ich hinzufügen.) Eine überschreibende Methode ist jedoch auch eine separate Methode, die zufällig denselben Namen hat. Die Magie des Überschreibens liegt nicht in irgendeiner zugrunde liegenden „Gleichheit“, sondern im Verhalten des Dispatch-Mechanismus.

    – Nate CK

    7. März 2012 um 13:57 Uhr


  • Dies super.touchMe();

    – Yousha Aleayoub

    31. Oktober 2018 um 13:08 Uhr

Benutzer-Avatar
aiobe

Private Methoden können nicht überschrieben werden (private Methoden werden nicht vererbt!) Tatsächlich macht es keinen Unterschied, ob Sie eine private Methode final deklarieren oder nicht.

Die beiden Methoden, die Sie deklariert haben, Boom.touchMe und Boom.Inner.touchMe sind zwei völlig getrennte Methoden die zufällig dieselbe Kennung haben. Die Tatsache, dass super.touchMe bezieht sich auf eine andere Methode als touchMeist nur weil Boom.Inner.touchMe Schatten Boom.touchMe (und nicht, weil es sie überschreibt).

Dies kann auf verschiedene Weise nachgewiesen werden:

  • Wie Sie selbst festgestellt haben, wird sich der Compiler beschweren, wenn Sie die Methoden auf öffentlich ändern sind versucht plötzlich, eine endgültige Methode zu überschreiben.

  • Wenn Sie die Methoden privat halten und die hinzufügen @Override Anmerkung, der Compiler wird sich beschweren.

  • Wie Alpian betont, wenn Sie die werfen Boom.Inner widersprechen a Boom Objekt (((Boom) inner).touchMe()) das Boom.touchMe aufgerufen wird (wenn es tatsächlich überschrieben wurde, spielt die Besetzung keine Rolle).

Verwandte Frage:

  • Private Methoden endgültig machen?

  • Ich kann mich in dieser Hinsicht irren, aber ich glaube, dass ein Schlüsselmissverständnis darin besteht super.touchMe() bedeutet “Rufe die Methode auf, die diese Methode überschreibt.” Während es oft so funktioniert, bedeutet es wirklich “Rufen Sie die touchMe() Methode in der Klasse, die diese Klasse erweitert.” Deshalb können Sie aufrufen super.touchMe() – es hat zufällig auch eine Methode (mit derselben Signatur).

    – corsiKa

    1. März 2012 um 21:06 Uhr


  • Ja dank! Ich hab es jetzt. Als ich es veröffentlichte, bekam ich den Kompilierungsfehler.

    – schick

    1. März 2012 um 21:11 Uhr

  • Es ist auch leicht zu erkennen, dass Inner Boom nicht überschreibt, das Hinzufügen von @Override zur Methode erzeugt einen Compilerfehler.

    – TDJoe

    1. März 2012 um 21:13 Uhr

  • Von dem Java-Sprachspezifikation: “Mitglieder einer Klasse, die als privat deklariert sind, werden nicht von Unterklassen dieser Klasse geerbt.” Hinter den Kulissen, wann Inner.touchMe() Anrufe super.touchMe()generiert der Compiler eine Zugriffsmethode mit einem eindeutigen Namen mit Standardzugriff (Paket) in der äußeren Klasse, die den Aufruf an die private Methode weiterleitet. Das ändert sich dann super.touchMe() um die Accessor-Methode aufzurufen.

    –Ted Hopp

    1. März 2012 um 23:10 Uhr

Ich denke, die Tatsache, dass es hier wirklich zwei getrennte Methoden gibt, wird gut demonstriert, indem Sie Ihre main wie folgt ändern:

public static void main(String... args) {
    Boom boom = new Boom();
    Boom.Inner inner = boom.new Inner();
    inner.touchMe();
    System.out.println("And now cast it...");
    ((Boom)(inner)).touchMe();
}

Das druckt jetzt:

super::I am not overridable!
sub::You suck! I overrided you!
And now cast it...
super::I am not overridable!

Und der Grund, dass der Anruf an super arbeitet in Inner liegt daran, dass Sie nach einer Methode mit dem Namen suchen touchMe in deiner Superklasse (Boom), die tatsächlich existiert und für die sichtbar ist Inner wie es in der gleichen Klasse ist.

Private Methoden sind für Unterklassen oder tatsächlich jede andere Klasse unsichtbar, sodass sie denselben Namen haben können, sich aber nicht gegenseitig überschreiben.

Versuchen Sie, die Annotation @Override hinzuzufügen – Sie erhalten einen Compilerfehler.

  • “Private Methoden sind unsichtbar für … jede andere Klasse” – außer und bis Sie Reflexion in Betracht ziehen.

    – Benutzer

    2. März 2012 um 8:55 Uhr


  • Stimmt – aber ich denke, das liegt außerhalb des Rahmens der ursprünglichen Frage und würde das übergeordnete Problem nicht beeinflussen.

    – DNS

    2. März 2012 um 9:06 Uhr


Sie können die Methode überschreiben, da dies der Fall ist private zu jeder Klasse.

Sie haben gerade eine andere Methode mit demselben Namen deklariert. Sie können privates Mitglied der Klasse aufrufen, da die innere Klasse selbst Mitglied der Klasse ist. Hoffe, diese Modifikation wird es im Detail erklären.

public class Boom {

    private final void touchMe() {
        System.out.println("super [touchMe] ::I am not overridable!");
    }

    public void overrideMe(){
        System.out.println("super [overrideMe]::I am overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub [touchMe]::You suck! I overrided you!");
        }

        public void overrideMe(){
            System.out.println("sub [overrideMe] ::I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();

        inner.touchMe();

        Boom newBoom = inner;
        newBoom.touchMe();
        newBoom.overrideMe();
    }
}



super [touchMe] ::I am not overridable!
sub [touchMe]::You suck! I overrided you!
super [touchMe] ::I am not overridable!
sub [overrideMe] ::I overrided you!

1125510cookie-checkWarum kann die innere Klasse die private final-Methode überschreiben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy