Pregunta

El compilador de eclipse se niega a compilar el siguiente código, indicando que el campo s no es visible. (El compilador Aspect J de IBM también se niega, declarando que " s no se pudo resolver ") ¿Por qué?

public class Test {

    String s;

    void foo(Object o) {
        String os = getClass().cast(o).s;
    }
}

Los estados de la especificación del lenguaje Java:

  

De lo contrario, decimos que hay por defecto   acceso, que está permitido sólo cuando   el acceso se produce desde dentro de la   Paquete en el que se declara el tipo.

De la forma en que lo entiendo, el campo se declara y se accede a él en la misma unidad de compilación, por lo tanto, dentro del mismo paquete, y por lo tanto debería estar accesible.

Aún más extraño, ¿agregar un downcast desde ? extiende Test a Test hace que el campo esté visible, es decir, que el siguiente código compile:

public class Test {

    String s;

    void foo(Object o) {
        Test t = getClass().cast(o);
        String os = t.s;
    }
}

¿He tropezado con un error del compilador o no he entendido bien las especificaciones de Java?

Editar: Estoy en otra computadora ahora. Aquí, javac acepta el código, pero eclipse todavía no lo hace. Versiones en esta máquina:

  

Plataforma Eclipse

     

Versión: 3.4.2 ID de compilación:   M20090211-1700

JDK 1.6.0

Editar 2 De hecho, javac acepta el código. Lo había probado ejecutando la compilación ant, que utiliza el compilador Ascpect J de IBM ...

¿Fue útil?

Solución

Prueba esto:

void foo(Object o) {
    Test foo = getClass().cast(o);
    String so = foo.s;
}

[Editar para aclarar]:

getClass (). cast (o) devuelve un objeto del tipo ' capture # 1-of? extiende Test 'y no Test . Entonces, el problema está relacionado con los genéricos y cómo el compilador lo trata. No conozco los detalles de la especificación sobre genéricos, pero dado que algunos compiladores (de acuerdo con los comentarios que aparecen aquí) aceptan su código, este es un agujero de bucle en la especificación o algunos de estos compiladores no están completamente de acuerdo con la especificación. / p>

[Últimos pensamientos]: Creo que el compilador de eclipse es en realidad (con cuidado) correcto aquí. El objeto o puede de hecho ser una extensión de Test (y definido en otro paquete) y el compilador no tiene forma de saber si ese es realmente el caso o no. Por lo tanto, lo trata como el peor caso de una instancia de una extensión definida en otro paquete. Habría sido súper correcto si agregar un calificador final a la clase Prueba hubiera permitido el acceso al campo s , pero no lo hace.

Otros consejos

Bueno, veamos. Diría que el compilador no puede garantizar correctamente que alguna entidad dentro del paquete llamará a foo () y, por lo tanto, no puede garantizar que s esté visible. Por ejemplo, añadir

protected void bar() {
    foo();
}

y luego en alguna subclase Banana en otro paquete

public void quux() { bar(); }

y oops! getClass () produce Banana , que no puede ver s .

Editar: En cierto sentido, other.package.Banana no tiene un campo s . Si Banana estuviera en el mismo paquete, aún podría tener su propia propiedad s , y tendría que referirse a la Prueba de s a través de super .

No puedo reproducir lo que estás diciendo. Ambos se compilan bien para mí sin advertencia, error o cualquier cosa con javac directamente.

WinXP, javac 1.6.0_16


No lo intenté con eclipse (v3.4.1, ID de compilación: M20080911-1700) y para el primero dice:

The field Test.s is not visible

Al menos para el nivel de conformidad del compilador 1.6 y 1.5. Lo gracioso es que, si nos fijamos en las opciones de Arreglo rápido, enumera una resolución de Cambiar a 's' . Lo que por supuesto no resuelve el problema. Por lo tanto, el compilador de eclipse y el generador Quick-fix " " parece que tienen diferentes puntos de vista sobre esto también ;-)


Para el nivel de conformidad del compilador 1.4 (como era de esperar) en eclipse para el primero que recibo

s cannot be resolved or is not a field

y para la segunda me sale

Type mismatch: cannot convert from Object to Test

Si especifico -source 1.4 y target -1.4 en la línea de comando directamente javac dice que para el primero

cannot find symbol

y para la segunda me sale

incompatible types

En realidad, en casi todos los casos, excepto cuando los Genéricos lo requieren, es mejor (y más seguro) usar el operador de Java. Lo comenté aquí . El operador de cast de Java se ve más detallado, pero es la herramienta correcta aquí.

Reemplazar el método cast con el operador compila perfectamente en Eclipse.

public class Test {

    String s;

    void foo(Object o) {
        String os = ((Test) o).s;
    }
}

Creo que alphazero es correcto aquí , que Eclipse es demasiado cauteloso.

Muy raro. Por una razón desconocida (para mí), el compilador de eclipse requiere una conversión explícita:

void foo(Object o) {
    String os = ((Test)getClass().cast(o)).s;
}

Mientras que el código se compila perfectamente sin el elenco con JDK de Sun (estoy ejecutando la versión 1.6.0_16 en GNU / Linux).

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