2010-09-17 9 views
36

Qui intendo davvero identità-uguaglianza.Java garantisce Object.getClass() == Object.getClass()?

Ad esempio, verrà sempre stampato true?

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

Se una classe (1) non sovrascrive il metodo equals (Object); e (2) non è una sottoclasse di una classe che sovrascrive il metodo equals (Object), quindi questa classe utilizza il metodo equals (Object) definito nella classe Object root - che utilizza l'operatore di identità ==. – emory

+12

@emory: Penso che il tuo commento sia sbagliato. Il '==' in questo frammento esegue sempre il confronto di riferimento, e l'operatore non può essere sovraccaricato per invocare 'equals' invece. Inoltre, 'java.lang.Class' è' final' quindi non puoi sovrascrivere i suoi 'equals'. – polygenelubricants

risposta

40

Sì, i token di classe sono univoci (per qualsiasi classloader specificato, ovvero).

I.e. riceverai sempre un riferimento allo stesso oggetto fisico nello stesso reame del classloader. Tuttavia, un diverso programma di caricamento delle classi carica un token di classe diverso, in connessione con il fatto che la stessa definizione di classe è ritenuta diversa se caricata da due distinti classloader.

Vedere this earlier answer of mine per una dimostrazione di questo.

8

Sì.

L'oggetto Classe restituito è l'oggetto bloccato dai metodi statici sincronizzati della classe rappresentata.

se fosse possibile tornare più istanze, quindi

public static synchronized void doSomething() {..} 

non sarebbe thread-safe.

+2

Un altro indizio è che javadoc dice che 'getClass' restituisce" _The_ Oggetto classe che rappresenta la classe di runtime di questo oggetto "... non" _A_ Oggetto classe ... ". –

14

Per due istanze di classe X,

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

solo se

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

Nota: Class.getClassLoader() possono restituire NULL che implica il ClassLoader bootstrap.

+0

Ottimo modo di metterlo – slezica

+0

@ McDowell, il tuo ultimo paragrafo è sbagliato. 'ClassLoader.getSystemClassLoader' non è lo stesso del programma di caricamento di classe bootstrap. Se '.getClassLoader()' restituisce null, significa che la classe viene caricata dal programma di caricamento di classe bootstrap. 'ClassLoader.getSystemClassLoader' non restituirà null. – Pacerier

+0

@Pacerier grazie per averlo indicato – McDowell

2

È garantito per classloader, come indicato nel JVM specification:

primo luogo, la macchina virtuale Java determina se ha già registrato che L è un caricatore iniziatore di una classe o interfaccia indicato con N. In tal caso, questo tentativo di creazione non è valido e il caricamento genera un'eccezione di collegamento.

Cioè, se una classe loader (L) cerca di bypassare predefinita Class casi caching, e rendere la JVM caricare il byte[] definizione più di una volta per il nome stessa classe (N), un LinkageError saranno gettati da la JVM.

Ad esempio, implementare un caricatore classe che chiama defineClass(...) ogni volta loadClass(...) viene richiamato (bypassando la cache predefinito):

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); 
    } 
} 

e questo è ciò che accade:

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) 

Acclamazioni

Problemi correlati