Me suena a: println(null.CONSTANTE);

Hoy tuve una extraña experiencia a retornar el valor de una constante mediante reflexion, algo asi como lo hace el getElementById en el javascript, despues de unas lineas lo hice funcionar (es csa facil) pero me llamo la atencion la forma en que se puedehacer

        public static String getByName(String name) throws Exception {
                return (String) LaCase.class.getField("ID_BLAH_BLAH_" + name).get(null);
        }

(Bueno en mi caso se desean obtener puros String)

la cosa es que me llamo la atencion cuando hice el ...get(null); senti que ibaa tronar y que no deberia ser asi pero funciono, yo lo que veo es que tiene cierta logica porque las constantes estan definidas asi:

        public final static String
                        ID_BLAH_BLAH_AAA = "065408879506640-S8",
                        ID_BLAH_BLAH_BBB = "XXXX",
                        ID_BLAH_BLAH_CCC = "YYY",
                        ID_BLAH_BLAH_DDD = "ZZZ",
                        ID_BLAH_BLAH_FFF = "...."
                        // ... (mil mas)
                        ;

lo que me dice es que por ser estaticas no necesitan instancia alguna para ser accesibles... pero por otra parte se esa obteniendo el valor de un objeto que es null... por ejemplo:

                ...println(LaClase.getByName("DDD"));

el codigo anterior creo que puede ser similar a este (porque estas obteniendo el valor de una clase cuya insancia es null:

                LaClase c = new LaClase();
                xx = null;
                ...println (xx.ID_BLAH_BLAH_DDD);

y aunque sea null no hay ningun NullPointerException... Se me hace curioso, esto me suena a println(null.CONSTANTE). Existe alguien que tambien se le haga raro?...

.
.
.
.

Pues es eso 'nomas, se me hizo raro! (me suenta un poco a contradiccion)... que piensan ustedes?

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de rodrigo salado anaya

static xxxx

Pues solo por poner un ejemplo de lo que dice @java.daba.doo:

public class Main {
    public static void main(String[] args) throws Exception {
        //System.out.println(NewClass.string1);
        //System.out.println(NewClass.string2); // ERROR
       
       
        Object obj1 = NewClass.class.getField("string1").get(null);
        System.out.println((String)obj1);

        Object obj2 = NewClass.class.getField("string2").get(null);
        System.out.println((String)obj2);

    }
}

class NewClass {

    public static String string1 = "xxx-xxx-xx-x";
    public final String string2 = "yyy-yy-yy-y";
}

run:
xxx-xxx-xx-x
Exception in thread "main" java.lang.NullPointerException
        at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:36)
        at sun.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:20)
        at java.lang.reflect.Field.get(Field.java:358)
        at esnull.Main.main(Main.java:20)
Java Result: 1

Ammm si no mal recuerdo en un libro leí algo de esto, y resulta que estos atributos de las clases son conocidos también como 'variable de clase' y son accesibles para todas las instancias, no recuerdo bien pero todas tiene acceso a ellas ( algo así como su propia copia), y no es necesario incluso crear una instancia de ellas para usarlas.

Esta padre el post. saludos a todos : )

Imagen de rodrigo salado anaya

Esta liga respon...

A lo que voy es que me hacia

A lo que voy es que me hacia ruido eso de pner null a la instancia de la cal quieres obtener el valor, que digo que me figura algo como null.CONSTANTE y todo eso porque en los estaticos no puedes usar el this... No se si me exprese mal, quiero decir que sintacticamente yo lo veo raro como se obtiene e valor de una constante (convencional) mediante reflexion

Lo que dices Rodrigo, esta aqui... (digamos que son aspectos basicos de Java)

Not all combinations of instance and class variables and methods are allowed:

  • Instance methods can access instance variables and instance methods directly.
  • Instance methods can access class variables and class methods directly.
  • Class methods can access class variables and class methods directly.
  • Class methods cannot access instance variables or instance methods directly—they must use an object reference. Also, class methods cannot use the this keyword as there is no instance for this to refer to.

fente: http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html

En otras palabras

En otras palabras esto:

class N {
    static String hola = "Hola";

    public static void main( String ... args ) {
        N nulo = null;
        System.out.println( nulo.hola );
    }
}

Es extraña la forma en que la funcionan los atributos de clase en Java. A ver si en el spec dice algo al respecto.

Por lo pronto lo que sí sé es

Por lo pronto lo que sí sé es que:

N nulo = null;

y

N noNulo = new N();

nulo.hola;
noNulo.hola;

Dan lo mismo cuando se trata de atributos de clase, son ignorados y reemplazados directamente por:

N.hola;

Por eso no sale el Npe, pero a ciencia cierta no sé que regla del lenguaje aplica ahí.

Imagen de beto.bateria

Cierto

Tal vez mas tarde explique eso de static como lo entiendo, es algo muy interesante, y que ocupo mucho. Les dejo por mientras:

http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html

Lo interesante tambien son los metodos estaticos (tal ves el mas famoso sea System.out.print()).

Ok, esto ya llego al final.

Ok, esto ya llego al final. la escencia es que de un objeto null se pueda extraer informacion. Lo interesante viene aqui:

Static hace nuestra constante como una prpiedad de clase y no de instancia.

No podemos hacer null.ID_BLAH_BLAH_AAA porque para empezar null no es algo tipado (es como decir que quieres un taco de carne pero no dices de que: si de perro, rata, gato, pollo, humano, marciano, programador java... etc).

ID_BLAH_BLAH_AAA es una constante de clase lo que significa que no necesitas instancia para acceder a ella (pero si necesitas referenciar a la clase de la cual obtienes el "valor de la cosntante de clase")

Entonces es por esa logica que puedes hacer LaClase.ID_BLAH_BLAH_AAA en donde estas obteniendo el valor de la constante de clase (no instanciada) y en el caso de la reflexion tampoco necesitas instancia y es por eso que puedes llamar a get(null)

Dice: Dame el valor de ID_BLAH_BLAH_AAA de "LaClase" cuya instancia sea: null

LaCase.class.getField("ID_BLAH_BLAH_AAA").get(null);

Es importnante notar que si se define el objeto del que se extrae la propiedad "de clase"

si se pudiera representar directamente creo que si seria algo asi:

(null <LaClase>).BLAH_BLAH_AAA

pero como null no puede ser tipado (porque no tiene sentido hacerlo aunque algo tipado SI puede ser null) hay que invocar la referencia nula de la clase:

LaClase.BLAH_BLAH_AAA

(porque si pones una variable tipo LaClase sin el final por ejemplo notaras que su valor por default es null... eso sucede en todas las propiedades que se definan fuera de los metodos de las clases (se autoasigna su valor default... dentro de los metodos es otra historia)

El realidad esto es un concepto basico que ejemplifica la pregunta: ¿que significa "static"?

Imagen de ezamudio

System.out.println()

beto.bateria: Eso no es un método estático. println() es un método de instancia, de la clase java.io.PrintStream. La clase System tiene una variable estática llamada out de tipo PrintStream.

No sé a qué te refieras con que usas mucho "eso de static"...

Imagen de bferro

La regla que aplica

En el cóidgo que Oscar pone de ejemplo:

class N {
    static String hola = "Hola";
    public static void main( String ... args ) {
        N nulo = null;
        System.out.println( nulo.hola );
    }
}

la regla que aplica es la que debe aplicar si la variable es estática, acceder a ella de manera directa sin importar lo que hay antes del operador punto (.), aunque lo que hay antes de ese operador puede provocar un efecto lateral, devolviendo siempre un objeto de clase N. Si esto no sucede el compilador anuncia el error.

El valor null puede ocupar el lugar que el corresponde a un objeto. El compilador no ejecuta, solamente comprueba sintaxis y semántica. Por esa razón,

N nulo = null;
nulo.toString();

son dos sentencias sintáctica y semánticamente correctas. La segunda provocará el disparo de una excepción.
Pero, la sentencia

null.toString()

no la admite el compilador, porque null no puede ser dereferenciado.

Por ejemplo, puedo escribir

(null instanceof Object)?true:false;

y el resutlado por supuesto es false.

Sin embargo no puedo escribir

5 instanceof Object)?true:false;

Todos los lenguajes que trabajan con apuntadores le dan un tratamiento diferente a null que a los valores de los tipos primitivos.

@bferro exacto! lo mismo

@bferro exacto! lo mismo sucede por ejemplo con

( ( N ) null ).hola;

Me parece que eso

Me parece que eso descomponiendolo en lineas es lo mismo que hacer:

N n = null;
n.hola

y si, claro que es valido!

(null instanceof

(null instanceof Object)?true:false;

Claro que es false porque null en java no tiene tipo: ni object

y

5 instanceof Object)?true:false;

¿sera por que pones u primitivo? Eso si lo detecta el compilador

me suena como cuando haces algo "iegal" que es valido sintacticamente

        do{
                // nada
        }while(1 == 1);
               
        System.out.println("");
}

Eso por ejemplo genera un lindisimo : "unreachable statement" al poner System.out.println(""); despues del do-while... a que voy con esto? que aun asi hay cosas que si se vaidan en tiempo de compilacion y creo que lo que mecniona bferro es un poco por eso pues un primitivo lo comparas con otro primitivo y del mismo tipo aunque hay "cosas que parecen raras" cuando haces char=int... para oros casos podriamos eso de las clases envolventes

Imagen de ezamudio

autoboxing

Raro que no funcione el autoboxing en (5 instanceof Object). Supongo que solamente se activa en asignaciones a variables y recepción de parámetros.

a lo que me referia

a lo que me referia es
 Integer = 5 y de ahi aplicar e instanceof, claro ahi ya 5 no es un primitivo sino un objeto

Imagen de bferro

"unreachable statement" es un error semántico y ....

"unreachable statement" es un error semántico y aunque la sintaxis es correcta, el compilador también realiza análisis semántico y por eso anuncia el error. Puedes "repasar" los errores semánticos usando Jakes como compilador.
Otro ejemplo sencillo de error semántico es al asignación entre tipos incompatibles, aunque la expresión tenga una sintaxis correcta.

Ah jijos, que raro!

Por cierto, ahora estaba buscando algo para complementar otro post de @OscarRyz ( http://www.javamexico.org/foros/java_standard_edition/listar_todos_los_g... ) y me encontre con algo que suena muy loco.

En esta liga publican algo (que bueno no va muy ad hoc con lo del titulo) que me llamo la atencion una linea en especial.

Quedamos que en la linea que escribio @bferro 5 instanceof Object)?true:false; marcaba un error semantico según yo argumentando que era un tipo primitivo que se pretendia comparar con un objeto... hasta ahí todo bien (parecia todo OK, pero hoy me encuentro con algo (que la verdad desconocía) que puedes hacer esto int.class entonces como sospechas:

Raro que no funcione el autoboxing

pero lo que me saca de onda es si de int puedes tener su class entonces quiere decir que lo puedes procesar como objeto (que pienso eso es util para el autoboxing)... entonces por que chihuahuas no funcionara?... ahora, será correcto que los primitivos tienen un tipo de clase?

Imagen de ezamudio

Consistencia

Si mal no recuerdo, metieron eso del .class a los primitivos por consistencia, eso viene desde mucho antes del autoboxing y se usa para el mapeo entre los primitivos y sus envoltorios. int.class == Integer.TYPE

Imagen de bferro

literales clases

Java como todo lenguaje hace uso de literales.
Un grupo de esos literales son los literales clases y dentro de los literales clases están aquellos para los tipos primitivos y para void (Java considera que Void (con mayúscula) es un "pseudo tipo".

Es el caso de  int.class que aquí se menciona. El literal int.class es la referencia a un objeto de tipo Class<Integer> (con anterioridad a la técnica de genéricos y autoboxing era un tipo de Class). El objeto void.class es de tipo Class<Void>

Para la reflexión son necesarios estos literales clases para los tipos primitivos; por ejemplo cuando se quiere expresar la firma de un método que se quiere obtener por reflexión y que admite argumentos de tipos primitivos.

A pesar de que JLS establece de que int.class es de tipo Class<Integer>, sigue manteniendo la distinción entre primitivos y objetos. Es un reflejo de no tratar a los primitivos como objetos y buscar algo que los pueda tratar de manera uniforme.
Va un ejemplo:

public class Main {
  public static void main(String[] args) throws Exception{
    Method[] intMethods = int.class.getMethods();
    System.out.println("¿int Methods? = " +intMethods.length);
    Method[] integerMethods= Integer.class.getMethods();
    System.out.println("¿Integer Methods? = "+integerMethods.length);
    System.out.println("Signature = " +IntegerReflection.class.getMethod("intReflection", int.class,Integer.class));
  }
}
class IntegerReflection{
  public void intReflection(int parameter1, Integer parameter2){

  }
}

Imprime
¿int Methods? = 0
¿Integer Methods? = 41
Signature = public void reflexion.IntegerReflection.intReflection(int,java.lang.Integer)

A ver entonces, un compilador

A ver entonces, un compilador de un lenguaje de programación con tipeo estático puede validar durante la compilación errores semánticos como los aquí descritos y/o hacer transformaciones cuando sabe que va a suceder con el resultado.

Por ejemplo, lo que mencionaron 5 instanceof Object, sabe que el 5 es una literal y que nunca va a ser un object y manda el error. También sabe que el println que no va a llegar después de un while infinito. O por ejemplo este otro:

class R {
    double i = ( 1 + 2 * 3 / 4 - 5 ) /  0.0;
}

Es transformado por el compilador en esto:

class R {
    double i = Double.NEGATIVE_INFINITY;
}

Aunque esto último no es privativo del tipeo estático.

Imagen de bferro

Los compiladores siempre hacen validación semántica

Con independencia del tipado, los compiladores siempre realizan análisis semántico y evalúan lo evaluable en tiempo de compilación. Esto último sigue determinadas reglas.