2009-09-29 4 views
3

En Java et en C#, il est possible d'invoquer une méthode privée par réflexion (comme indiqué ci-dessous).Pourquoi pouvez-vous réfléchir et appeler une méthode (pas si) privée en Java et .Net

  • Pourquoi est-ce autorisé?
  • Quelles sont les conséquences de cela?
  • Devrait-il être retiré dans une future version de la langue?
  • Est-ce que d'autres langues/plates-formes permettent cela? Si je cette classe dans Java et C#

Voici l'exemple

public class Foo 
{ 
    private void say() { WriteToConsoleMethod("Hello reflected world"); } 
} 

WriteToConsole() est un langage spécifique, alors que je peux exécuter ce qui suit pour appeler la méthode say() privée:

C#

Foo f = new Foo(); 
var fooType = f.GetType(); 
var mi = fooType.GetMethod("say", BindingFlags.NonPublic | BindingFlags.Instance); 
mi.Invoke(f, null); 

Java

Foo f = new Foo(); 
Method method = f.getClass().getDeclaredMethod("say", null); 
method.setAccessible(true); 
method.invoke(f, null); 

Comme vous pouvez le voir, il est pas évident, mais ce n'est pas difficile non plus.

Répondre

17

À la fois Java et .NET, ceci n'est autorisé que si vous avez des autorisations suffisantes. Le code que vous exécutez directement depuis la ligne de commande fonctionne (généralement) en mode "confiance totale". Si vous essayez de faire la même chose dans des environnements plus restrictifs, cela échouera. Le contrôle d'accès concerne plus l'encapsulation que la sécurité. Si vous travaillez à pleine confiance, vous avez probablement accès suffisant pour lancer des méthodes natives pour fouiner mémoire directement ... de toute façon

  • Pourquoi est-il permis? Parfois, cela peut être utile. Il doit être traité avec précaution, mais cela peut être utile.

  • Quelles sont les ramifications? Votre code devient fragile; vous interagissez avec un type d'une manière inattendue.

  • Devrait-il être retiré dans une future version de la langue? Il s'agit d'une fonctionnalité de plate-forme plutôt que d'une fonctionnalité de langue en premier lieu, mais non je ne pense pas qu'il devrait être supprimé.

  • Est-ce que d'autres langues/plate-formes le permettent? Je ne suis pas sûr ... je ne serais pas surpris cependant.

+3

"Parfois ça peut être pratique" - J'ai trouvé l'occasion où je l'ai utilisé la réflexion pour tester des méthodes privées. On pourrait argumenter que, étant encapsulé, il devrait être testé à travers les interfaces fournies et les méthodes publiques. Mais parfois, ces méthodes privées encapsulent un petit peu de logique complexe avec quelques cas intéressants où des tests unitaires directs améliorent vraiment le développement. Alors oui, peut être pratique parfois! – Matt

4

Ceci est autorisé car les restrictions d'accès ne sont pas censées être une mesure de sécurité. C'est un peu comme mettre des verrous sur votre maison - ils sont dissuasifs, mais ils ne font rien contre quelqu'un qui veut utiliser un bélier pour briser la porte.

+0

Les restrictions d'accès sont une mesure de sécurité principale lors de l'exécution de code mobile. –

+1

@Tom - c'est pourquoi dans ces environnements il y aura presque certainement un gestionnaire de sécurité présent qui rejettera l'opération. Voir, par exemple, docs pour setAccessible dans http://java.sun.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html. –

+2

Je dirais que c'est plus comme mettre un * signe * sur une fenêtre en disant "s'il vous plaît utiliser la porte" - il correspond mieux à l'idée d'interfaces accessibles au public par rapport aux détails de mise en œuvre. Et puis courir avec un gestionnaire de sécurité, c'est comme mettre un videur avec un gros bâton en face de l'enseigne pour s'assurer que les gens le suivent ... :-) –

1

Si pour une raison quelconque, vous devez vous assurer que les appelants inappropriés ne peuvent pas appeler une certaine méthode (par exemple s'il y a une sorte de mot de passe/risque de sécurité), un coup d'oeil au code de la sécurité d'accès en .net. Il existe un moyen de dire à l'exécution de ne permettre à une méthode d'être appelée que par les appelants ayant une signature Authenticode spécifique.

-1

Le modèle privé/protégé/public de C++ est devenu populaire parce que C++ est devenu populaire, pas parce que c'était une bonne idée.

Il existe de nombreuses bibliothèques qui définissent des méthodes privées qui ne devraient pas avoir; certains programmeurs vont presque tout mettre au privé sans comprendre pourquoi vous le feriez, et certains IDE créent un code d'échafaudage avec un ensemble privé alors que ce ne devrait probablement pas être le cas. Le résultat est que beaucoup de bibliothèques ont de bonnes idées utiles, mais ont des erreurs quelque part dans leurs méthodes, et souvent ces méthodes sont marquées privées. Le problème avec private/protected/public et les contraintes normales qui les accompagnent est que vous ne pouvez pas planifier l'utilisation future de votre code par tout le monde. Même si vous avez réussi à écrire du code sans bug (ce qui n'est pas le cas), les bibliothèques populaires trouveront toujours des utilisations futures que vous n'aviez pas prévues. L'auteur ne peut pas déterminer quelles méthodes et variables devront être consultées, remplacées, modifiées, etc. pour chaque utilisation future au moment où elles l'écrivent. C'est juste trop de responsabilité.

Donc, cette astuce de réflexion que vous avez trouvé rompt ce modèle, mais la vérité est qu'il devrait probablement être plus facile à casser, pas plus difficile. Je ne considérerais pas cela comme un bug.

En fait, dans .Net, vous pouvez utiliser Reflector pour aller encore plus loin et éviter les appels de réflexion en temps réel dans votre code, pour éviter les pertes de performance subies lorsque vous trouvez un code bogué privé. Si vous le faites, essayez d'éviter les déclarations privées dans le nouveau code que vous écrivez, pour être gentil avec l'auteur suivant qui exploite votre travail.

Questions connexes