Il est garanti par classloader, comme indiqué dans le JVM specification:
Tout d'abord, la machine virtuelle Java détermine si elle a déjà enregistré que L est un chargeur d'amorçage d'une classe ou une interface notée N. Si tel est le cas, cette tentative de création n'est pas valide et le chargement génère une erreur LinkageError.
Autrement dit, si un chargeur de classe (L) tente de contourner par défaut Class
instances de mise en cache, et rendre la machine virtuelle Java charge plus d'une fois définition byte[]
pour le même nom de classe (N), un LinkageError
sera lancé par la JVM.
Par exemple, mettre en œuvre un chargeur de classe qui appelle defineClass(...)
chaque fois loadClass(...)
est invoquée (sans passer par la mise en cache par défaut):
public class ClassloaderTest {
private static final byte[] CLASS_DEF = readClassBytes();
private static byte[] readClassBytes() {
try {
InputStream is = ClassloaderTest.class.getResourceAsStream("ClassloaderTest.class");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
} catch (IOException ex) {
throw new AssertionError();
}
}
private static ClassLoader createNonCachingClassloader() {
return new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("classloader.ClassloaderTest")) {
return defineClass(name, CLASS_DEF, 0, CLASS_DEF.length);
} else {
return getParent().loadClass(name);
}
}
};
}
public static void main(String[] args) throws Exception {
ClassLoader cl = createNonCachingClassloader();
Class<?> cl1 = cl.loadClass("classloader.ClassloaderTest");
Class<?> cl2 = cl.loadClass("classloader.ClassloaderTest");
System.out.println(cl1==cl2);
}
}
et voici ce qui se passe:
Exception in thread "main" java.lang.LinkageError: loader (instance of classloader/ClassloaderTest$1): attempted duplicate class definition for name: "classloader/ClassloaderTest"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at classloader.ClassloaderTest$1.loadClass(ClassloaderTest.java:53)
at classloader.ClassloaderTest.main(ClassloaderTest.java:64)
Vive
Si une classe (1) ne remplace pas la méthode equals (Object); et (2) n'est pas une sous-classe d'une classe qui substitue la méthode equals (Object) alors cette classe utilise la méthode equals (Object) définie dans la classe Object racine - qui utilise l'opérateur d'identité ==. – emory
@emory: Je pense que votre commentaire est faux. Le '==' dans cet extrait effectue toujours une comparaison de référence, et l'opérateur ne peut pas être surchargé pour appeler 'equals' à la place. De même, 'java.lang.Class' est' final', donc vous ne pouvez pas surcharger 'equals'. – polygenelubricants