2010-09-17 15 views
36

Realmente me refiero a igualdad de identidad aquí.¿Java garantiza que Object.getClass() == Object.getClass()?

Por ejemplo, ¿siempre se imprimirá lo siguiente verdadero?

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

Si una clase (1) no anula el método equals (Object); y (2) no es una subclase de una clase que anula el método equals (Object), entonces esta clase usa el método equals (Object) definido en la clase raíz Object - que usa el operador == identity. – emory

+12

@emory: Creo que tu comentario es incorrecto. El '==' en este fragmento siempre realiza una comparación de referencia, y el operador no puede sobrecargarse para invocar 'iguales' en su lugar. Además, 'java.lang.Class' es' final' por lo que no puede anular su 'igual'. – polygenelubricants

Respuesta

40

Sí, los tokens de clase son únicos (para cualquier cargador de clases dado, eso es).

I.e. siempre obtendrá una referencia al mismo objeto físico dentro del mismo dominio de cargador de clases. Sin embargo, un cargador de clases diferente cargará un token de clase diferente, junto con el hecho de que la misma definición de clase se considera diferente cuando es cargada por dos cargadores de clase distintos.

Consulte this earlier answer of mine para una demostración de esto.

8

Sí.

El objeto de Clase devuelto es el objeto que está bloqueado por métodos estáticos sincronizados de la clase representada.

si era posible volver varias instancias, entonces

public static synchronized void doSomething() {..} 

no sería seguro para subprocesos.

+2

Otra pista es que el javadoc dice que 'getClass' devuelve el objeto" _The_ Class que representa la clase de tiempo de ejecución de este objeto "... no" _A_ Class object ... ". –

14

Durante dos instancias de la clase X,

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

sólo si

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

Nota: Class.getClassLoader() puede devolver null que implica el cargador de clases de arranque.

+0

Excelente manera de ponerlo – slezica

+0

@McDowell, Su último párrafo es incorrecto. 'ClassLoader.getSystemClassLoader' no es lo mismo que el cargador de clases bootstrap. Si '.getClassLoader()' devuelve nulo, significa que la clase es cargada por el cargador de clases bootstrap. 'ClassLoader.getSystemClassLoader' no devolverá nulo. – Pacerier

+0

@Pacerier gracias por señalar eso – McDowell

2

Está garantizado por cargador de clases, como se indica en la JVM specification:

En primer lugar, la Máquina Virtual de Java determina si ya se ha registrado que L es un cargador de iniciación de una clase o interfaz denotado por N. Si es así, este intento de creación no es válido y la carga arroja un LinkageError.

Es decir, si un cargador de clases (L) intenta eludir predeterminado Class casos el almacenamiento en caché, y hacer que la JVM carga el byte[] definición más de una vez por el mismo nombre de la clase (N), un LinkageError serán arrojados por la JVM.

Por ejemplo, implementar un cargador de clases que llama defineClass(...) cada vez loadClass(...) se invoca (sin pasar por el almacenamiento en caché por defecto):

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

y esto es lo que sucede:

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) 

Saludos

Cuestiones relacionadas