Warum können wir keine schwächeren Privilegien in der Unterklasse zuweisen?

8

Ich habe eine Klasse mit einer Methode, deren Zugriffsspezifizierer standardmäßig öffentlich ist. Nun möchte ich diese Klasse in einer Unterklasse erweitern und diese Methode überschreiben, um den Zugriffsbezeichner "privat" zu haben. Beim Kompilieren dieses Codes erhalte ich einen Kompilierungsfehler:

  

"versucht, schwächere Zugriffsrechte zuzuweisen".

Könnte mir bitte jemand erklären, was mit der Zuweisung schwacher Privilegien in einer Unterklasse nicht stimmt?

Hier ist der Code, der den Kompilierungsfehler verursacht hat:

%Vor%     
syam 07.07.2013, 07:36
quelle

7 Antworten

25

Die kurze Antwort ist, dass es nicht erlaubt ist, weil es die Typ-Ersetzbarkeit unterbrechen würde; siehe auch das Liskow-Substitutionsprinzip (LSP) .

Der Punkt ist, dass der Polymorphismus in Java (und anderen Programmiersprachen) davon abhängt, dass Sie eine Instanz einer Unterklasse behandeln können, als ob sie eine Instanz der Oberklasse wäre. Aber wenn die Methode in der Unterklasse eingeschränkt ist, finden Sie, dass der Compiler nicht herausfinden kann, ob die Zugriffsregeln erlauben, dass eine Methode aufgerufen wird ...

Nehmen wir an, Ihr Beispielcode sei legal:

%Vor%

Wenn Sie die Entscheidung darauf basieren, ob s2.foo() für den deklarierten Typ von s2 zulässig ist, dann erlauben Sie einen Aufruf einer private -Methode von außerhalb der Abstraktionsgrenze von Subclass .

Wenn Sie die Entscheidung auf den tatsächlichen Typ des Objekts beziehen, auf das sich s2 bezieht, können Sie die Zugriffsprüfung nicht statisch durchführen. Der Fall s3 macht dies noch deutlicher. Der Compiler hat absolut keine Möglichkeit zu wissen, was der tatsächliche Typ des von someMethod zurückgegebenen Objekts sein wird.

Zugriffsprüfungen, die zu Laufzeitausnahmen führen können, wären eine Hauptursache für Fehler in der Java-Anwendung. Die hier diskutierte Sprachbeschränkung vermeidet dieses unangenehme Problem.

    
Stephen C 07.07.2013 07:39
quelle
7

Sie können den Zugriff nicht einschränken, da Sie in der Superklasse bereits mehr Zugriff zugelassen haben. z.B.

%Vor%

Der Zugriff von sc wird durch den Typ des Verweises sc bestimmt, nicht darauf, was er referenziert, da der Compiler in keinem Fall wissen kann, welchen Typ das Objekt zur Laufzeit hat. Damit dies eine sichere Annahme ist, muss die Unterklasse den vom Elternteil gegebenen Vertrag erfüllen oder sie ist keine gültige Unterklasse. Dies ist nicht anders als das übergeordnete Element, das besagt, dass eine Methode implementiert ist, aber die Unterklasse sagt, dass sie nicht (oder nicht verfügbar) ist.

Sie könnten dies umgehen, indem Sie sagen, dass Sie nur über das Elternobjekt auf die Unterklassenmethode zugreifen können, nicht direkt. Das Problem dabei ist, dass Sie nicht wissen, wann ein Elternteil eine Methode hinzufügen darf, und wenn Sie eine Methode private erstellen, tun Sie dies, weil Sie möchten, dass es privat und nicht anders zugänglich ist.

BTW Sie können immer noch auf eine private Methode über Reflektion zugreifen, was den Nebeneffekt hat, dass sie alle Arten von Problemen für die JVM verursacht. z.B. Es muss private Methoden beibehalten, obwohl es möglicherweise feststellt, dass es normalerweise nicht normal aufgerufen werden kann.

Kurz gesagt, Sie wollen Code, was bedeutet, was es sagt, und keine gespaltene Persönlichkeit haben. Es ist entweder Paket lokal oder es ist privat nicht etwas dazwischen, aber auch nicht wirklich. Dies ist kein Problem in der anderen Richtung. d.h. wenn die Unterklasse öffentlich ist. Es bedeutet nur, dass die Unterklasse an mehr Stellen als der Elternteil verwendet werden kann, genauso wie sie mehr Methoden implementieren kann.

    
Peter Lawrey 07.07.2013 07:39
quelle
5

Wenn dies erlaubt wäre, gäbe es eine Hintertür, über die Sie Methoden aufrufen könnten, auf die nicht zugegriffen werden sollte.

Sagen wir, dass dies erlaubt ist

%Vor%

obj.method wäre möglich, weil method() in der Klasse Super public ist. Aber es sollte nicht erlaubt sein,  weil obj sich wirklich auf eine Instanz von Sub bezieht, und in dieser Klasse ist die Methode geschützt!

Um einen Aufruf auf eine Methode in der Klasse Sub einzuschränken, die von außen nicht erreichbar sein soll, wird diese Einschränkung gesetzt.

    
Vikas V 07.07.2013 07:47
quelle
1

Das Beschränken des Zugriffsmodifizierers einer Superklassenmethode ist eine ungültige Außerkraftsetzung, weil sie den Superklassenvertrag bricht und das Substitutionsprinzip, dh ein Unterklassenobjekt IS-A Superklassenobjekt , ungültig macht gut.

%Vor%

Wenn dies erlaubt wäre, würde der obige Client-Code brechen, weil Ihre SubClass diese Methode nicht public hat.

Referenz:
Liskow-Substitutionsprinzip

    
Ravi Thapliyal 07.07.2013 07:41
quelle
0

Abgesehen von den offensichtlichen Problemen bei der Verwendung solcher Konstruktionen (wie Peter Lawrey in seiner Antwort darauf hingewiesen hat), lesen Sie auch die Theorie dahinter: LSP , was bedeutet, dass Sie den Haupttyp durch seine Unterklasse ersetzen können.

    
Zavior 07.07.2013 07:40
quelle
0

Ich denke, die kurze Antwort ist, dass die Autoren des Compilers die Regeln auf diese Weise festgelegt haben. LSP hat nichts mit dem Problem zu tun.

Der einzige Grund, warum ich an diese Einschränkung denken kann, ist, dass, wenn eine Unterklasse von einer Schnittstelle als Client-Programmierer abstammt, Sie alle zugänglichen Methoden der Schnittstelle von einer Referenz auf die abgeleitete Klasse aufrufen können .

Angenommen, Sie könnten den Code schreiben, den das OP angezeigt hat. Wenn Sie einen Verweis auf die abgeleitete Klasse haben, sollten Sie in der Lage sein, alle öffentlichen Mitglieder der abgeleiteten Klasse aufzurufen (obwohl es in diesem Fall keine gibt). Übergeben Sie den Verweis als Parameter jedoch an eine Methode, die einen Verweis auf die Basisklasse verwendet, und die Methode erwartet, dass sie eine beliebige öffentliche oder Paketmethode aufruft, nämlich foo . Dies ist der LSP, nach dem andere Mitwirkende suchen!

C ++ Beispiel:

%Vor%     
quamrana 07.07.2013 13:51
quelle
0

Beim Aufruf der dynamischen Methode wird der Aufruf der überschriebenen Methode zur Laufzeit statt zur Kompilierzeit aufgelöst. Es basiert auf dem Objekt, auf das zum Zeitpunkt des Aufrufs verwiesen wird ...

Nun nehmen wir an, dass eine schwächere Zugriffsberechtigung erlaubt war und schreiben folgende Anweisung in eine andere Klasse Ihres Codes:

%Vor%

Wenn java während der Laufzeit auf die Anweisung ref.foo() stößt, muss sie foo() von Subclass ... aufrufen, aber foo() Methode der Unterklasse wird in Ihrem Code als privat deklariert und private kann nicht sein Außerhalb der eigenen Klasse aufgerufen..so jetzt gibt es einen Konflikt und es würde Laufzeit Ausnahme ...

führen     
mihir S 29.08.2013 13:47
quelle

Tags und Links