J'ai créé une classe "String" et l'ai placée dans le package "Java" [en fait, je voulais créer Java.lang pour voir quelle classe est chargée par classLoader
Une fois qu'une classe est chargée dans une machine virtuelle, le fichier même classe (je répète, la même classe) ne sera pas chargé à nouveau
cité de oreilly]. Mais cette chose plus tard, pourquoi sur ce cours je reçois
Java.lang.SecurityException: Nom du package interdit: Java
Pour quelle raison de sécurité, Java ne me permet pas d’avoir une classe dans Java package? Que pourrait-on faire s'il n'y a pas de chèque?
Le code utilisateur est jamais autorisé à placer des classes dans l’un des packages Java standard. De cette manière, le code utilisateur ne peut pas accéder aux classes/méthodes/champs privés du paquet dans l'implémentation Java. Certains de ces objets privés à un paquet permettent d'accéder aux éléments internes de la machine virtuelle Java. (Je pense à SharedSecrets
en particulier.)
Premièrement, ces types de restrictions sont en place pour appliquer le sandbox Java. Autrement dit, exécuter du code non approuvé dans un environnement approuvé. Par exemple, exécuter une applet à partir d'un site (sur lequel vous ne faites pas nécessairement confiance), sur votre ordinateur (l'environnement de confiance) dans votre navigateur. Le but est d'empêcher le code non approuvé d'accéder aux éléments de paquet privé qui pourraient l'aider à échapper au bac à sable.
Normalement, ces restrictions sont appliquées par SecurityManager. Elles ne devraient donc pas se produire lorsque vous exécutez votre propre application sur la ligne de commande (à moins que vous ne spécifiiez explicitement d'utiliser un SecurityManager). Lorsque vous contrôlez l'environnement, vous pouvez simplement modifier la définition de String.class dans le fichier rt.jar de votre Java (et techniquement, vous ne pouvez pas savoir exactement ce que dit la licence). Comme je l'ai dit, les restrictions sont normalement dans SecurityManager, mais cette règle particulière concernant les packages Java. * Est dans la classe ClassLoader.
Pour répondre à votre question: Je suppose que Java. * Check existe à cause de A) des raisons historiques B) quelque part dans le noyau Java, il existe un contrôle sur le nom de la classe, quelque chose comme: Toute classe qui Commencez par Java. * Obtenez un traitement spécial.
Cependant, considérez que même si vous parveniez à créer une classe appelée Java.lang.String, celle-ci ne serait pas la même que celle de Java.lang.String définie par le noyau Java. Ce serait juste une classe avec exactement le même nom. L'identité de classe est plus que le nom de la classe, même si cela peut être difficile à percevoir si vous ne jouez pas vraiment avec ClassLoaders.
Ainsi, une classe chargée par le chargeur de classes de l'application dans le package Java.lang n'aurait pas accès au contenu de base du package Java.lang.
Pour illustrer cela, essayez de créer une classe appelée javax.swing.JButton avec une méthode main et exécutez-la. Vous obtiendrez un Java.lang.NoSuchMethodError: main
. C'est parce que Java trouve le "vrai" JButton avant votre classe et que le vrai JButton n'a pas de méthode principale.
Dans une application autonome Java, vous pouvez peut-être contourner cette restriction en appelant directement l'une des méthodes defineClassx natives privées via l'utilisation de reflect et de setAccessible.
BTW: Il est garanti que le noyau Java.lang.String sera chargé avant l’exécution de votre code car il est référencé partout, vous n’y arriveriez pas d’abord avec votre code utilisateur. La JVM est configurée dans une certaine mesure avant même d'essayer de charger votre classe, et encore moins de l'exécuter.
Vous ne pouvez pas avoir de nom de package "Java. *". Ceci est en fait codé en dur dans le noyau Java, vous ne pouvez donc même pas accorder à un gestionnaire de sécurité l'autorisation de le contourner (voir ClassLoader :: preDefineClass (...))
Java
est un nom de package réservé. Seules les classes de la machine virtuelle Java peuvent résider dans ce package.
Si quelqu'un pouvait écrire dans le package Java, les bibliothèques pourraient remplacer arbitrairement les classes Java essentielles par leurs propres implémentations. Cela pourrait donner lieu à de nombreuses réflexions, allant de la modification des principales fonctionnalités de Java à l’exécution de code malveillant.
Un programme pourrait contourner les mesures de sécurité s'il pouvait redéfinir les classes principales de la JVM avec des versions de chevaux de Troie. Par exemple, String est utilisé pratiquement partout.
De la ClassLoader.defineClass(..)
javadoc:
... Le nom de classe spécifié ne peut pas commencer par "Java.", Car toutes les classes des packages "Java. * Ne peuvent être définies que par le chargeur de classes d'amorçage
et
Lève: ... SecurityException - Si l'on tente d'ajouter cette classe à un package contenant des classes signées par un ensemble de certificats différent de celui de cette classe, ou si le nom de la classe commence par "Java".
Probablement pendant le refactoring/le correctif en appliquant/etc. vous avez ajouté au nom de package Word 'Java', qui est généralement un dossier contenant des packages.
Vous pouvez donc terminer avec la structure: Src-> main-> Java-> Java.com.votre paquetage.name
Cela peut également arriver pour le test: Src-> main-> test-> Java-> Java.com.votrepackage.name
Vérifiez-le dans votre IDE et supprimez "Java". partie
Un extrait de la méthode preDefineClass
de Java.lang.ClassLoader
:
/* Determine protection domain, and check that:
- not define Java.* class,
- signer of this class matches signers for the rest of the classes in
package.
*/
private ProtectionDomain preDefineClass(String name,
ProtectionDomain pd)
{
...
// Note: Checking logic in Java.lang.invoke.MemberName.checkForTypeAlias
// relies on the fact that spoofing is impossible if a class has a name
// of the form "Java.*"
if ((name != null) && name.startsWith("Java.")) {
throw new SecurityException
("Prohibited package name: " +
name.substring(0, name.lastIndexOf('.')));
}
...
}
Notez que Java.lang.ClassLoader
est une classe abstraite, ce qui signifie qu’une sous-classe (par exemple, SecureClassLoader
) l’implémentera. Cependant, la méthode preDefineClass
est private
et ne peut donc pas être remplacée par une sous-classe.
preDefineClass
est appelé par la méthode defineClass
, qui est protected final
. Cela signifie que defineClass
est accessible aux sous-classes et qu'elles peuvent l'appeler, mais elles ne pourront pas modifier son implémentation.