Versteckt das Upcasting in Java die Methoden und Felder der Unterklasse?
Frage
Auf dem Programm, das ich schreibe, habe ich eine Klasse RestrictedUser
und Klasse User
das ist abgeleitet von RestrictedUser.
Ich versuche, die benutzerspezifischen Methoden durch Umwandlung zu verbergen RestrictedUser
aber wenn ich das Casting durchführe, sind die Benutzermethoden immer noch verfügbar.Auch wenn ich den Debugger ausführe, wird der Typ der Variablen als angezeigt User
.
RestrictedUser restricted = regularUser;
Versteckt das Upcasting in Java die Methoden und Felder der Unterklasse oder mache ich etwas falsch?Gibt es eine Problemumgehung?
Danke
Lösung
Wenn Sie versuchen würden, diesen Code auszuführen:
User user = new User(...);
RestrictedUser restricted = user;
restricted.methodDefinedInTheUserClass(); // <--
Sie würden einen Kompilierungsfehler erhalten.Das wird in keiner Weise, Form oder Form sicher sein, denn selbst wenn Sie es herumreichen würden RestrictedUser
zu, sagen wir, einer anderen Methode, diese Methode könnte Folgendes tun:
if (restricted instanceof User) {
User realUser = (User)restricted;
realUser.methodDefinedInTheUserClass(); // !!
}
und Ihr „eingeschränkter“ Benutzer ist nicht mehr so eingeschränkt.
Das Objekt wird im Debugger als angezeigt User
Objekt, weil es so ist User
Objekt, auch wenn die Objektreferenz in einem gespeichert ist RestrictedUser
Variable.Grundsätzlich werden durch das Einfügen einer Instanz einer untergeordneten Klasse in eine Variable mit dem Typ einer übergeordneten Klasse zwar die Methoden und Felder der Unterklasse „versteckt“, jedoch nicht sicher.
Andere Tipps
Ich bin nicht sicher genau das, was Sie als die Terminologie fragen Sie verwenden, ist ein wenig unklar, aber hier geht. Wenn Sie eine übergeordnete Klasse und eine Unterklasse haben, können Sie die Methoden in der Oberklasse aus der Unterklasse verstecken, indem sie privat zu machen. Wenn Sie auf der übergeordnete Klasse öffentliche Methoden müssen unsichtbar sein, Sie sind kein Glück. Wenn Sie die Unterklasse der Superklasse werfen dann die öffentlichen Methoden für die Unterklasse nicht mehr sichtbar sind.
Ein Vorschlag, die Ihnen helfen würden Zusammensetzung zu verwenden, anstatt Vererbung, extrahiert die empfindlichen Methoden in eine separate Klasse und dann eine entsprechende Instanz dieser Klasse in das Objekt einfügen nach Bedarf. Sie können Methoden aus der Klasse auf die injizierte Klasse delegieren, wenn Sie benötigen.
Du verwechselst statischen Typen und dynamischen Typen.
Statische Typ ist der Typ der Referenz. Wenn Sie up-Cast aus zu Base abgeleitet sind Sie den Compiler zu sagen, dass so weit wie Sie es wissen, wies die Sache an eine Base. Das heißt, Sie sind viel versprechend, dass das Objekt gerichtet entweder null oder eine Base ist, oder etwas von Base abgeleitet. Welches ist zu sagen, es Basis öffentliche Schnittstelle.
Sie werden nicht dann in der Lage sein, Methoden in Abgeleitet erklärt zu nennen (und in der Base nicht), aber wenn Sie irgendwelche Basismethoden von Abgeleitet überschrieben aufrufen, werden Sie überschriebene Version des Abgeleitet erhalten.
Wenn Sie die Unterklasse schützen müssen, können Sie das Delegieren Muster verwenden:
public class Protect extends Superclass { // better implement an interface here
private final Subclass subclass;
public Protect(Subclass subclass) {
this.subclass = subclass;
}
public void openMethod1(args) {
this.subclass.openMethod1(args);
}
public int openMethod2(args) {
return this.subclass.openMethod2(args);
}
...
}
Sie können denken, auch über die Verwendung von java .lang.reflect.Proxy
[]]
Peter Antwort und John Antwort korrekt ist: nur den statischen Typ Gießen wird nichts tun, wenn die tatsächliche Art des Objekts (die Client-Code werfen kann, Call Reflexionsmethoden auf, etc.) noch verfügbar ist. Sie haben die reale Art zu maskieren irgendwie (als Peter Antwort erwähnt).
Es ist eigentlich ein Muster, dies zu tun: Haben Sie einen Blick auf die unconfigurable*
Methoden in der Executors
Klasse, wenn Sie Zugriff auf den JDK-Quellcode.
Java
In Java können Sie nie „Ausblenden“ etwas von einem Objekt. Der Compiler kann vergessen, was Sie im Detail über den speziellen Fall wissen Sie haben. (Wie das, was Unterklasse ist es) Der Debugger weiß viel mehr als der Compiler, so wird es Ihnen sagen, was tatsächlichen Typ der aktuellen Instanz ist, was wahrscheinlich ist, was Sie erlebt haben.
OOP
Es klingt wie Sie Logik schreiben, welcher wissen muss, welche Art von Objekt Sie verwenden, die nicht in OOP empfohlen, aber oft aus praktischen Gründen erforderlich ist.
Die Beschränkung Adjektive
Wie ich in einem Kommentar auf die Frage gesagt, sollten Sie sich auf klar sein, was ist die Basisklasse hier. Intuitiv RestrictedUser sollte eine Unterklasse von Benutzern sein, da der Name eine spezielle Art schlägt. (Name mit einem zusätzlichen aktiven Adjective darauf.) In Ihrem Fall dieses besondere ist, da dies ein limitierender Adjektiv ist, die Sie Benutzer als Unterklasse von RestrictedUser lassen würden setzen völlig in Ordnung. Ich würde empfehlen, die beiden zu so etwas wie das Umbenennen. BasicUser / UserWithId und NonRestrictedUser die Begrenzung Adjektiv zu vermeiden, die die verwirrende Teil ist hier
Auch nicht versucht sein, zu denken, dass Sie entweder Methoden in einer anonymen Klasse verstecken. Zum Beispiel wird dies die Privatsphäre nicht bieten Sie erwarten:
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("Hello, world!");
}
public void secretSquirrel() {
System.out.println("Surprise!");
}
}
Sie können nicht in der Lage sein, die reale Art von run
zu nennen (um es direkt zu werfen), aber man kann immer noch seine Klasse mit getClass()
, und Sie können secretSquirrel
mit Reflexion nennen. (Auch wenn secretSquirrel
privat, wenn Sie keine SecurityManager
haben, oder wenn es eingerichtet wurde Zugänglichkeit zu ermöglichen, Reflexion kann auch private Methoden aufrufen.)
Ich glaube, Sie wahrscheinlich eine schlechte Namensgebung Wahl getroffen. Ich denke, würde RestrictedUser
eine Unterklasse von User
wäre, nicht umgekehrt, so dass ich UnrestrictedUser
als Unterklasse verwenden
Wenn Sie eine UnrestrictedUser
zu einem RestrictedUser
upCast, wird Ihre Referenz nur in der Lage sein, Methoden in RestrictedUser
erklärt zuzugreifen. Allerdings, wenn Sie es zurück zu einem UnrestrictedUser
niedergeschlagenen, haben Sie Zugriff auf alle Methoden haben. Da Java wissen Objekte, welche Art sie wirklich sind, alles, was eigentlich eine UnrestrictedUser
ist, kann immer auf sie geworfen werden zurück, egal, welche Art von Referenz Sie (auch eine Object
) verwenden. Es ist unvermeidbar, und ein Teil der Sprache. Allerdings Sie es hinter einer Art von Proxy verstecken konnte, aber in Ihrem Fall, dass wahrscheinlich Niederlagen der Zweck.
Auch in Java, alle nicht-statischen Methoden sind virtuelle standardmäßig. Dies bedeutet, dass wenn UnrestrictedUser
eine Methode in RestrictedUser
erklärt überschreibt, dann wird die UnrestrictedUser
Version verwendet werden, auch wenn man es durch eine RestrictedUser
Referenz zugreifen. Wenn Sie die übergeordnete Klasse-Version aufrufen müssen, können Sie eine nicht-virtuellen Anruf von RestrictedUser.variableName.someMethod()
aufrufen. Allerdings sollten Sie wahrscheinlich nicht sehr häufig verwenden (die am wenigsten der Gründe ist, dass es bricht Kapselung).
Ich denke, auch diese Frage eine andere Frage aufwirft. Wie planen Sie, diese Methode zu nennen? Es scheint wie eine Klasse-Hierarchie mit dem Subclassing neue Methode Signaturen führt wird instanceof prüft in Anrufer erfordern.
Können Sie Ihre Frage aktualisieren, ein Szenario zu schließen, wo Sie diese Methoden in Frage stellen würden? Vielleicht werden wir in der Lage sein, mehr zu helfen.
Die technische Antwort wurde von John Calsbeek gegeben. Ich möchte über das Design-Problem denken. Was Sie versuchen, oder einige Entwickler zu tun ist, einige Segment des Codes zu verhindern, von etwas über die User-Klasse kennen. Sie wollen, dass sie alle Benutzer zu behandeln, als ob sie RestrictedUsers waren.
Die Art und Weise, dass ist mit Berechtigungen tun würde. Sie müssen die Entwickler in Frage, die Zugriff auf die Benutzerklasse zu verhindern. Sie können wahrscheinlich, indem Sie es in einem Paket und die Beschränkung des Zugangs zu dem Paket tun.