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

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top