48 votes

Sensibilité à la casse des noms de classe Java

Si on écrit deux classes Java avec la même casse nom dans des répertoires différents, puis les deux classes ne sont pas utilisables au moment de l'exécution. (J'ai testé sur Windows, Mac et Linux avec plusieurs versions de la JVM HotSpot. Je ne serais pas surpris si d'autres machines virtuelles où ils sont utilisables simultanément.) Par exemple, si je crée une classe nommée a et un nommé A comme:

// lowercase/src/testcase/a.java
package testcase;
public class a {
    public static String myCase() {
        return "lower";
    }
}

// uppercase/src/testcase/A.java 
package testcase;
public class A {
    public static String myCase() {
        return "upper";
    }
}

Trois projets eclipse contenant le code ci-dessus sont disponibles à partir de mon site web.

Si vous essayez ce que j'appelle myCase sur les deux classes comme suit:

System.out.println(A.myCase());
System.out.println(a.myCase());

Le typechecker réussit, mais quand je lance le fichier de classe générer par le code directement au-dessus, j'obtiens:

Exception in thread "main" java.lang.NoClassDefFoundError: cas de test/Un (mauvais nom: testcase/a)

En Java, les noms sont en général sensibles à la casse. Certains systèmes de fichiers (par exemple Windows) sont insensibles à la casse, donc je ne suis pas surpris de ce comportement se produit, mais il semble mauvais. Malheureusement, les spécifications Java bizarrement non-commital sur les classes qui sont visibles. Le Langage Java Specification (JLS), Java SE 7 Édition (Section 6.6.1, page 166) dit:

Si une classe ou une interface de type est déclaré en public, alors il peut être consulté par tout code, à condition que l'unité de compilation (§7.3) dans lequel elle est déclarée est observables.

Dans la Section 7.3, la JLS définit l'observabilité d'une unité de compilation extrêmement vague:

Toutes les unités de compilation de la prédéfinis package java et de ses sous-lang et io sont toujours observables. Pour tous les autres paquets, le système hôte détermine les unités de compilation sont observables.

La Machine Virtuelle Java de Spécification est de la même manière vague (Section 5.3.1):

Les étapes suivantes sont utilisées pour charger et de créer ainsi la nonarray classe ou interface C notée par [nom binaire] N à l'aide de la classe de bootstrap loader [...] Sinon, la machine virtuelle Java passe l'argument N à un appel d'un méthode de la classe de bootstrap loader à la recherche d'une prétendue représentation de C dans une plate-forme de manière dépendante.

Tout cela conduit à quatre questions dans l'ordre décroissant d'importance:

  1. Sont-il des garanties sur les classes qui sont chargeables par la valeur par défaut de la classe loader(s) dans chaque JVM? En d'autres termes, puis-je mettre en œuvre un valide, mais dégénérée de la JVM, qui ne se charge pas toutes les classes à l'exception de ceux de java.lang et de java.io?
  2. S'il y a des garanties, le comportement dans l'exemple ci-dessus violent la garantie (c'est à dire le comportement d'un bug)?
  3. Est-il possible de faire un HotSpot de la charge a et A simultanément? Aurait écrit une classe personnalisée chargeur de travail?

19voto

Donal Fellows Points 56559
  • Sont-il des garanties sur les classes qui sont chargeables par la classe de bootstrap loader dans chaque JVM?

La base de pièces et de morceaux de la langue, en plus de soutenir la mise en œuvre des classes. Pas garanti de façon à inclure toute la classe que vous écrivez. (La normale de la JVM des charges de vos classes dans un autre chargeur de classe de bootstrap, et en fait la normale de chargeur de démarrage charge les classes d'un POT normalement, ce qui la rend pour le déploiement plus efficace qu'une vieille grosse structure de répertoire complet de classes.)

  • S'il y a des garanties, le comportement dans l'exemple ci-dessus violent la garantie (c'est à dire le comportement d'un bug)?
  • Est-il possible de faire "standard" Jvm charger un et Un à la fois? Aurait écrit une classe personnalisée chargeur de travail?

Java charge des classes par la cartographie du nom complet de la classe dans un nom de fichier qui est ensuite recherché dans le classpath. Ainsi, testcase.a va testcase/a.class et testcase.A va testcase/A.class. Certains systèmes de fichiers mélange de ces choses, et peut servir les autres quand on est demandé. D'autres l'obtenir droite (en particulier, la variante de la ZIP format utilisé dans les fichiers JAR est entièrement sensible à la casse et portable). Il n'y a rien que Java peut faire à ce sujet (même si un IDE pouvait s'en occuper pour vous, en gardant l' .class dossiers à l'extérieur du natif de FS, je ne sais pas si réellement faire et le JDK de l' javac plus n'est certainement pas que smart).

Cependant ce n'est pas le seul point à noter ici: fichiers de classe savoir en interne, quelle classe ils sont en train de parler. L'absence de l' attendu de la classe à partir du fichier signifie simplement que le chargement échoue, conduisant à l' NoClassDefFoundError que vous avez reçu. Ce que vous avez eu un problème (une erreur de déploiement dans au moins un certain sens) qui a été détecté et traité de manière robuste. Théoriquement, vous pourriez construire un chargeur de classe qui puisse s'occuper de ces choses, par l'observance de la recherche, mais pourquoi s'embêter? Mettre les fichiers de classe à l'intérieur d'un POT va arranger les choses beaucoup plus robuste; ceux-ci sont pris en charge correctement.

Plus généralement, si vous êtes en cours d'exécution dans ce problème pour de vrai beaucoup, prendre pour faire de la production s'appuie sur un Unix avec un système de fichiers sensible (un système CI comme Jenkins est recommandé) et de trouver que les développeurs sont de nommage des classes avec seulement des différences de cas et de les faire arrêter, que c'est très confus!

1voto

Tillmann Points 81

Donal beaux explication laisse peu à ajouter, mais permettez-moi de muse sur cette phrase:

... Des classes Java avec la même casse nom ...

Les noms et les Chaînes de caractères, en général, ne sont jamais insensibles à la casse en eux-mêmes, c'est seulement là que l'interprétation qui peut être. Et deuxièmement, Java ne fait pas une telle interprétation.

Donc, un bon phrasé de ce que vous aviez à l'esprit serait:

... Java des classes dont les représentations de fichiers de la casse du système de fichiers ont des noms identiques ...

-2voto

umlcat Points 2025

Ne pensez pas seulement sur les dossiers.

L'utilisation explicite des espaces de noms différents ("packages") pour vos classes, et peut-être utiliser des dossiers pour correspondre à vos classes.

Quand je parle de "packages", je ne veux pas "*.POT de fichiers, mais seulement le concept de:

package com.mycompany.mytool;

// "com.mycompany.mytool.MyClass"

public class MyClass
{
   // ...
} // class MyClass

Lorsque vous ne spécifiez pas un package pour votre code, la java des outils (compilateur, I. D. E., peu importe), supposons d'utiliser le même pour tous. Et, dans le cas de plusieurs autres classes, ils ont une liste de dossiers, où les chercher.

Les paquets sont comme des dossiers "virtuels" dans votre code, et s'appliquent à tous de votre colis sur votre chemin de classe ou de l'installation de Java. Vous pouvez avoir plusieurs classes, avec le même I. D., mais, si elles sont différentes, et que vous spécifiez le forfait à regarder, vous n'aurez pas de problème.

Juste mes 2 cents, pour votre tasse de café Java

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X