Question

Sur le programme que je vous écris, j'ai un RestrictedUser de classe et User de classe qui est dérivée de RestrictedUser. J'essaie de cacher les méthodes spécifiques à l'utilisateur par coulée à RestrictedUser mais quand je fais le casting des méthodes de l'utilisateur sont encore disponibles. Aussi quand je lance le débogueur le type de la variable est comme User.

RestrictedUser restricted = regularUser;

AMENAGE coulée en Java cache les méthodes de sous-classe et les champs ou que je fais quelque chose de mal? Y at-il une solution de contournement?

Merci

Était-ce utile?

La solution

Si vous deviez tenter d'exécuter ce code:

User user = new User(...);
RestrictedUser restricted = user;
restricted.methodDefinedInTheUserClass(); // <--

vous obtiendrez une erreur de compilation. Ce ne sera pas sûr de quelque manière, la forme ou la forme, parce que même si vous deviez passer autour du RestrictedUser, disons, une autre méthode, cette méthode pourrait faire ceci:

if (restricted instanceof User) {
    User realUser = (User)restricted;
    realUser.methodDefinedInTheUserClass(); // !!
}

et votre utilisateur « restreint » est pas limitée plus.

L'objet affiche dans le débogueur comme un objet User parce qu'il est comme objet User, même si la référence d'objet est stocké dans une variable RestrictedUser. En gros, mettre un exemple d'une classe d'enfants dans une variable avec un type de classe parent en effet « cacher » les méthodes et les champs de la sous-classe, mais pas en toute sécurité.

Autres conseils

Je ne sais pas exactement ce que vous demandez que la terminologie que vous utilisez est un peu incertain, mais va ici. Si vous avez une superclasse et une sous-classe, vous pouvez masquer les méthodes de la superclasse de la sous-classe en les rendant privée. Si vous avez besoin des méthodes publiques sur les superclasse être invisibles que vous êtes hors de la chance. Si vous lancez la sous-classe aux superclasse alors les méthodes publiques sur la sous-classe ne sont plus visibles.

Une suggestion qui pourrait vous aider serait d'utiliser la composition plutôt que l'héritage, extraire les méthodes sensibles dans une classe séparée puis insérez une instance appropriée de cette classe dans l'objet, au besoin. Vous pouvez déléguer des méthodes de la classe à la classe injectée si vous avez besoin.

Vous confondez type statique et type dynamique.

type statique est le type de la référence. Lorsque vous en coulée de dérivés à la base, vous indiquez au compilateur que, pour autant que vous et savez, la chose pointé est une base. Autrement dit, vous promettant que l'objet pointé est soit nul, ou une base, ou quelque chose provenant de la base. Ce qui veut dire, il a une interface publique de base.

Vous ne puis être en mesure d'appeler des méthodes déclarées dans dérivées (et non dans la base), mais lorsque vous appelez toutes les méthodes de base par redéfinis dérivés, vous aurez la version surchargée Dérivée de.

Si vous devez protéger la sous-classe, vous pouvez utiliser le modèle de délégué:

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

Vous pouvez aussi penser à utiliser java .lang.reflect.Proxy
[]]

réponse Peter et réponse John sont corrects: il suffit de jeter le type statique ne fera rien si le type réel de l'objet (dont le code client peut lancer à des méthodes de réflexion d'appel, etc.) est toujours disponible. Vous devez masquer le type réel en quelque sorte (comme la réponse de Pierre mentionne).

Il est en fait un modèle pour ce faire: un coup d'oeil sur les méthodes de unconfigurable* dans la Executors classe , si vous avez accès au code source JDK.

Java

En Java, vous ne pouvez jamais quelque chose « Masquer » d'un objet. Le compilateur peut oublier ce que vous savez en détail sur l'instance particulière que vous avez. (Comme quoi la sous-classe est) Le débogueur sait beaucoup plus que le compilateur, il vous dira quel type réel l'instance actuelle est, ce qui est probablement ce que vous vivez.

POO

On dirait que vous écrivez la logique qui a besoin de savoir quel type d'objet que vous utilisez qui n'est pas recommandé en POO, mais souvent nécessaire pour des raisons pratiques.

Interdire l'accès Adjectifs

Comme je l'ai dit dans un commentaire à la question, vous devriez être clair sur ce qui est la classe de base ici. Intuitivement RestrictedUser devrait être une sous-classe de l'utilisateur depuis son nom l'indique un type plus spécialisé. (Nom ayant un Adjectif actif supplémentaire à ce sujet.) Dans votre cas, c'est spécial puisque c'est un adjectif limite qui vous permettra de mettre l'utilisateur comme une sous-classe de RestrictedUser tout à fait bien. Je recommande de renommer les deux à quelque chose comme:. BasicUser / UserWithId et NonRestrictedUser pour éviter l'adjectif limite qui est la partie source de confusion ici

En outre, ne pas être tenté de penser que vous pouvez cacher des méthodes dans une classe anonyme soit. Par exemple, cela ne fournira pas la vie privée que vous attendez:

Runnable run = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, world!");
    }

    public void secretSquirrel() {
        System.out.println("Surprise!");
    }
}

Vous ne pouvez pas être en mesure de nommer le vrai type de run (afin de jeter directement à), mais vous pouvez toujours obtenir sa catégorie avec getClass(), et vous pouvez appeler secretSquirrel utilisant la réflexion. (Même si secretSquirrel est privé, si vous n'avez pas SecurityManager, ou si elle a été mise en place pour permettre l'accessibilité, la réflexion peut appeler des méthodes privées aussi.)

Je pense que vous avez probablement fait un mauvais choix de nom. Je pense que RestrictedUser serait une sous-classe de User, et non l'inverse, donc je vais utiliser UnrestrictedUser comme la sous-classe

Si vous upCast un UnrestrictedUser à un RestrictedUser, votre référence sera en mesure d'accéder à des méthodes déclarées dans RestrictedUser. Cependant, si vous baissés revenir à un UnrestrictedUser, vous aurez accès à toutes les méthodes. Étant donné que les objets Java savent quel type ils sont vraiment, tout ce qui est en fait un UnrestrictedUser peut toujours être jeté de nouveau à lui, peu importe quel type de référence que vous utilisez (même un Object). Il est inévitable et une partie de la langue. Cependant, vous pouvez le cacher derrière une sorte de procuration, mais dans votre cas que les défaites probablement dans le but.

En outre, en Java, toutes les méthodes non statiques sont virtuels par défaut. Cela signifie que si UnrestrictedUser remplace une méthode déclarée dans RestrictedUser, la version de UnrestrictedUser sera utilisé, même si vous y accédez par une référence RestrictedUser. Si vous avez besoin d'invoquer la version de la classe parent, vous pouvez effectuer un appel non virtuel en appelant RestrictedUser.variableName.someMethod(). Cependant, vous ne devriez probablement pas utiliser ce très souvent (la moindre des raisons étant qu'il casse l'encapsulation).

Je pense aussi que cette question soulève une autre question. Comment envisagez-vous d'appeler cette méthode? Il semble comme avoir une classe où heirarchy de nouvelles signatures subclassing introduit la méthode nécessitera instanceof contrôles dans les appelants.

Pouvez-vous mettre à jour votre question d'inclure un scénario dans lequel vous appelleriez ces méthodes en question? Peut-être que nous serons en mesure d'aider plus.

La réponse technique a été donnée par John Calsbeek. Je veux réfléchir à la question de la conception. Ce que vous essayez de faire est de prévenir un segment du code, ou certains développeurs, de savoir quoi que ce soit au sujet de la classe utilisateur. Vous voulez qu'ils traitent tous les utilisateurs comme si elles étaient RestrictedUsers.

La façon dont vous le faire est avec des autorisations. Vous devez éviter que les développeurs en question d'avoir accès à la classe utilisateur. Vous pouvez probablement le faire en le plaçant dans un paquet et de restreindre l'accès à l'ensemble.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top