2010-09-17 8 views
36

Je pense vraiment à l'égalité des identités ici.Est-ce que Java garantit que Object.getClass() == Object.getClass()?

Par exemple, est-ce que les éléments suivants seront toujours imprimés true?

System.out.println("foo".getClass() == "fum".getClass()); 
+0

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

+12

@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

Répondre

40

Oui, les jetons de classe sont uniques (pour tout chargeur de classe donné, c'est-à-dire).

I.e. vous obtiendrez toujours une référence au même objet physique dans le même domaine classloader. Cependant, un chargeur de classe différent chargera un jeton de classe différent, en conjonction avec le fait que la même définition de classe est réputée différente lorsqu'elle est chargée par deux chargeurs de classe distincts.

Voir this earlier answer of mine pour une démonstration de cela.

8

Oui.

L'objet Class retourné est l'objet qui est verrouillé par des méthodes synchronisées statiques de la classe représentée.

S'il était possible de revenir plusieurs instances, puis

public static synchronized void doSomething() {..} 

ne serait pas thread-safe.

+2

Un autre indice est que javadoc dit que 'getClass' renvoie" _The_ Class objet qui représente la classe d'exécution de cet objet "... not" _A_ Class object ... ". –

14

Pour deux instances de la classe X,

x1.getClass() == x2.getClass() 

que si

x1.getClass().getClassLoader() == x2.getClass().getClassLoader() 

Note: Class.getClassLoader() peut retourner null qui implique la ClassLoader d'amorçage.

+0

Excellente façon de le mettre – slezica

+0

@McDowell, Votre dernier paragraphe est faux. 'ClassLoader.getSystemClassLoader' n'est pas la même chose que le classloader bootstrap. Si '.getClassLoader()' renvoie null, cela signifie que la classe est chargée par le chargeur de classe bootstrap. 'ClassLoader.getSystemClassLoader' ne renverra pas de null. – Pacerier

+0

@Pacerier merci de souligner cela – McDowell

2

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

Questions connexes