2012-01-23 10 views
25

Solo con el experimento, descubrí que los métodos no estáticos de Java anulan todos los mismos métodos nombrados en el alcance, incluso en el contexto estático. Incluso sin permitir la sobrecarga de parámetros. ComoImportaciones estáticas de Java

import java.util.Arrays;  
import static java.util.Arrays.toString; 

public class A { 
    public static void bar(Object... args) { 
     Arrays.toString(args); 
     toString(args);  //toString() in java.lang.Object cannot be applied to (java.lang.Object[]) 
    } 
} 

No puedo encontrar nada sobre esto en la especificación. ¿Es esto un error? Si no es así, ¿hay alguna razón para implementar un lenguaje como ese?

UPD: Java 6 no compila este ejemplo. La pregunta es, ¿por qué?

+0

Parece estar refiriendo a su súper objeto 'toString()' –

+2

en mi humilde opinión, toda la funcionalidad de importación estática es un mal concepto, contaminando los espacios de nombres y la lectura del código messing. No seas flojo, no es demasiado difícil escribir la clase/interfaz adjunta de una función estática, tenemos IDEs para eso. Intenta evitar el uso de importaciones estáticas. – buc

+0

@Jigar Joshi, Se ve tan. Pero no puedo encontrar nada. Y más, no podemos llamar 'Object.toString' desde el contexto estático, así que no veo ninguna lógica en este comportamiento. –

Respuesta

21

La explicación es sencilla aunque no cambia el hecho de que el comportamiento es muy poco intuitivo:

Al resolver el método que se invoca lo primero que hace el compilador se encuentra el ámbito más pequeño que encierra que tiene un método del nombre correcto. Solo entonces vienen otras cosas como resolución de sobrecarga y co en el juego.

Ahora, lo que está sucediendo aquí es que el ámbito de delimitación más pequeño que contiene un método toString() es de clase A, que lo hereda de Object. Por lo tanto, nos detenemos allí y no buscamos más. Tristemente, el próximo compilador intenta encontrar el mejor ajuste de los métodos en el alcance dado y nota que no puede llamar a ninguno de ellos y da un error.

Lo que significa Nunca importar estáticamente métodos con un nombre que es idéntico a un método en el objeto, porque métodos que son naturalmente en su alcance tienen prioridad sobre las importaciones estáticas (el JLS describe método sombreado en detalle, pero para este problema, creo que es mucho más simple recordar eso).

Editar: @alf amablemente enviado la parte correcta de la JLS que describes the method invocation para aquellos que quieren la imagen completa. Es bastante complejo, pero el problema tampoco es simple, así que eso es de esperar.

+4

El enlace JLS, en caso de que lo necesite - http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.1 – alf

+0

@alf Gracias, eso hace que la respuesta sea mucho mejor ahora . Lo habría agregado yo mismo si hubiera sabido dónde encontrar la descripción en JLS. – Voo

4

No es una anulación. Si funcionara, this.toString() seguiría teniendo acceso al método A en lugar de Arrays.toString, como sería el caso si se hubiera producido una anulación.

El language specification explica que las importaciones estáticas sólo afectan a la resolución de static métodos y tipos:

Una sola estática e importación declaración d en una unidad de compilación c del envase p que importa un campo denominado n sombras del declaración de cualquier campo estático llamado n importado por una declaración static-import-on-demand en c, en todo c.

Una sola declaración d de importación estática en una unidad de compilación c del paquete p que importa un método llamado n con firma s shadows la declaración de cualquier método estático nombrado n con firma s importada por una importación estática- declaración bajo demanda en c, en todo c.

Una sola-static-importación declaración d en una unidad de compilación c de paquete p que importa un tipo llamado n sombras las declaraciones de:

  • cualquier estática tipo llamado n importado por a-importación estática declaración bajo demanda en c.
  • cualquiera nivel superior tipo (§7.6) nombrado n declarado en otra unidad de compilación (§7.3) de p.
  • cualquier tipo llamado n importado por una declaración de tipo de importación a pedido (§7.5.2) en c. en todo c.

importaciones estáticas no sombra métodos no estáticos o tipos interiores.

Por lo tanto, el toString no sombrea el método no estático. Como el nombre toString puede hacer referencia a un método no estático de A, no puede hacer referencia al método static de Arrays y, por lo tanto, toString se une al único método denominado toString que está disponible en el alcance, que es String toString(). Ese método no puede tomar ningún argumento para que obtenga un error de compilación.

Section 15.12.1 explica la resolución del método y debería haber sido completamente reescrita para permitir el sombreado de nombres de métodos no disponibles dentro de los métodos static pero no en los métodos member.

Supongo que los diseñadores de idiomas querían mantener simples las reglas de resolución de métodos, lo que significa que el mismo nombre significa lo mismo si aparece en un método static o no, y lo único que cambia es qué están disponibles.

+0

Excepto que como el método 'bar' es estático, no hay instancia para invocar' toString() 'al – chrisbunney

+0

@StasKurilin, editado. –

+2

@StasKurilin [par. 6.3.1] (http://java.sun.com/docs/books/jls/third_edition/html/names.html#34133) lo explica más claramente. Dice que la declaración del método de instancia 'Object.toString()' sombrea * cualquier otro método * en su alcance. Esto incluye la importación estática para 'Arrays.toString (Object [])'. Esto significa que, efectivamente, la importación estática * no tiene efecto *: el compilador ni siquiera considerará resolver la llamada al método. – millimoose

0

No creo que sea un error o algo diferente de la importación normal. Por ejemplo, en caso de importación normal, si tiene una clase privada con el mismo nombre que la importada, la importada no se reflejará.

1

Si intenta siguiente aspecto similar código entonces no recibirá ningún error de compilación

import static java.util.Arrays.sort; 
public class StaticImport { 
    public void bar(int... args) { 
     sort(args); // will call Array.sort 
    } 
} 

La razón de que esto compila y el suyo no es que el toString() (o cualquier otro método definido en la Objeto de clase) todavía tienen alcance a la clase Object debido a que Object es el padre de tu clase. Por lo tanto, cuando el compilador encuentra la firma correspondiente de esos métodos de la clase Object, genera un error de compilación. En mi ejemplo, dado que la clase Object no tiene el método sort(int[]), el compilador lo relaciona con la importación estática .

Cuestiones relacionadas