Pregunta

Solo por experimento descubrí que los métodos no estáticos de Java anulan todos los métodos con el mismo nombre en su alcance, incluso en un 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 las especificaciones.¿Es esto un error?Si no es así, ¿hay alguna razón para implementar un lenguaje como ese?

ACTUALIZACIÓN:Java 6 no compila este ejemplo.La pregunta es: ¿por qué?

¿Fue útil?

Solución

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 va a invocar, lo primero que hace el compilador es encontrar el alcance más pequeño que contenga un método con el nombre correcto.Sólo entonces vienen otras cosas como la resolución de sobrecarga y el juego.

Ahora lo que está sucediendo aquí es que el alcance más pequeño que contiene un toString() El método es la clase A que lo hereda de Object.Por eso nos detenemos allí y no buscamos más.Lamentablemente, a continuación, el compilador intenta encontrar el mejor ajuste de los métodos en el alcance dado y se da cuenta de que no puede llamar a ninguno de ellos y genera 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 dentro del alcance tienen prioridad sobre las importaciones estáticas. (El JLS describe el método de seguimiento en detalle, pero para este problema creo que es mucho más sencillo recordarlo).

Editar: @alf amablemente envió la parte correcta del 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 esperarse.

Otros consejos

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 una anulación.

El especificación del idioma explica que las importaciones estáticas sólo 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 una declaración de importación estática bajo demanda en c, a lo largo de c.

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

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:

  • cualquier tipo estático llamado n importado mediante una declaración de importación estática bajo demanda en c.
  • cualquier tipo de nivel superior (§7.6) denominado n declarado en otra unidad de compilación (§7.3) de la p.
  • cualquier tipo llamado sustantivo, masculino— importado mediante una declaración de tipo de importación bajo demanda (§7.5.2) en c.a lo largo de c.

Las importaciones estáticas no ocultan métodos no estáticos ni tipos internos.

Entonces el toString no ensombrece el método no estático.Desde el nombre toString puede referirse a un método no estático de A, no puede referirse a la static método de Arrays y por lo tanto toString se une al único método nombrado toString que está disponible en alcance, que es String toString().Ese método no puede aceptar ningún argumento, por lo que aparece un error de compilación.

Sección 15.12.1 explica la resolución del método y tendría que haberse reescrito por completo para permitir el sombreado de nombres de métodos no disponibles dentro static métodos pero no dentro member métodos.

Supongo que los diseñadores del lenguaje querían mantener simples las reglas de resolución de métodos, lo que significa que el mismo nombre significa lo mismo ya sea que aparezca en un static método o no, y lo único que cambia es cuáles están disponibles.

Si intentas seguir aspecto similar código entonces tu no lo hará obtener cualquier 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 que el toString() (o cualquier otro método definido en la clase Objeto) todavía tienen como alcance la clase Objeto debido a que Objeto es el padre de su clase.Por lo tanto, cuando el compilador encuentra la firma coincidente de esos métodos de la clase Objeto, genera un error del compilador.En mi ejemplo, dado que la clase Objeto no tiene sort(int[]) método, por lo tanto, el compilador lo relaciona correctamente con el importación estática.

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, ya que se importó uno, el importado no se reflejará.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top