Importaciones estáticas de Java


Solo por experimento descubrí que los métodos no estáticos de Java anulan todos los métodos con el mismo nombre en el ámbito, incluso en el contexto estático. Incluso sin permitir la sobrecarga de parámetros. Como

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 spec. ¿Es un micrófono? Si no lo es, ¿hay alguna razón para implementar un lenguaje como ese?

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

Author: Lion, 2012-01-23

4 answers

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

Al resolver el método que se va a invocar lo primero que hace el compilador es encontrar el ámbito de inclusión más pequeño que tenga un método con el nombre correcto. Solo entonces vienen otras cosas como la resolución de sobrecarga y co en el juego.

Ahora lo que está sucediendo aquí es que el ámbito de inclusión más pequeño que contiene un método toString() es la clase A que lo hereda de Object. Por lo tanto nos detenemos allí y no busques más. Tristemente después el compilador intenta encontrar el mejor ajuste de los métodos en el ámbito 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 sea idéntico a un método en Objeto, porque los métodos que están naturalmente en el alcance tienen prioridad sobre las importaciones estáticas (el JLS describe el método de sombreado en detalle, pero para este problema creo que es recuerde que).

Editar: @alfamablemente envió la parte derecha de la JLS que describe la invocación del método para aquellos que quieren la imagen completa. Es bastante complejo, pero el problema tampoco es simple, así que es de esperar.

 22
Author: Voo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:24:00

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

La especificación del lenguaje explica que las importaciones estáticas solo afectan la resolución de static métodos y tipos:

Una declaración de importación estática única d en una unidad de compilación c del paquete p que importa un campo llamado n oculta la declaración de cualquier campo estático llamado n importado por a static-import-on-demand declaration in c, throughout c.

Una única declaración de importación estática d en una unidad de compilación c del paquete p que importa un método llamado n con firma s sombrea la declaración de cualquier método estático llamado n con firma s importado por una declaración de importación estática en c, a lo largo de c.{[16]]}

Una declaración de importación estática única d en una unidad de compilación c del paquete p que importa un tipo llamado n oculta las declaraciones de:

  • any static type named n imported by a static-import-on-demand declaration in c.
  • any top level type (§7.6) named n declared in another compilation unit (§7.3) of p.
  • any type named n imported by a type-import-on-demand declaration (§7.5.2) in c. a lo largo de c.

Las importaciones estáticas no sombrean métodos no estáticos o tipos internos.

Por lo que el toString no sombra de la método no estático. Dado que el nombre toString puede referirse a un método no estático de A, no puede referirse al método static de Arrays y, por lo tanto, toString se une al único método llamado toString que está disponible en el ámbito, que es String toString(). Ese método no puede tomar ningún argumento por lo que se obtiene un error de compilación.

La sección 15.12.1 explica la resolución del método y tendría que haber sido completamente reescrita para permitir el remedo de nombres de métodos no disponibles dentro de los métodos static pero no dentro de los métodos member.

Mi conjetura es que los diseñadores del lenguaje querían mantener las reglas de resolución de métodos simples, 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 cuáles están disponibles.

 4
Author: Mike Samuel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-23 13:48:03

Si intentas seguir código de aspecto similar entonces no obtendrá ningún error del compilador

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

La razón por la que esto se compila y el tuyo no es porque el toString() (o cualquier otro método definido en la clase Object) todavía están dentro del ámbito de la clase Object debido a que Object es el padre de tu clase. Por lo tanto, cuando el compilador encuentra la firma coincidente de esos métodos de la clase Object, entonces da error al compilador. En mi ejemplo since Object class no tiene sort(int[]) método por lo tanto el compilador coincide correctamente con la importación estática .

 1
Author: anubhava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-23 13:43:35

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á.

 0
Author: yadab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-23 13:34:55