2009-05-11 22 views

risposta

55

Suppongo che dipenda dal tipo e dal compilatore (a pensarci bene, sicuramente no!). Il compilatore di Sun allinea le costanti primitive, ma non so se rimuovono completamente la voce dalla classe. Lo scoprirò.

Modifica: Sì, è ancora possibile accedervi anche se sono in linea. classe di test:

public class ReflectionConstantTest { 
    private static final int CONST_INT = 100; 
    private static final String CONST_STRING = "String"; 
    private static final Object CONST_OBJECT = new StringBuilder("xyz"); 
    public static void main(String[] args) throws Exception { 
     int testInt = CONST_INT; 
     String testString = CONST_STRING; 
     Object testObj = CONST_OBJECT; 
     for (Field f : ReflectionConstantTest.class.getDeclaredFields()) { 
      f.setAccessible(true); 
      System.out.println(f.getName() + ": " + f.get(null)); 
     } 
    } 
} 

uscita:

 
CONST_INT: 100 
CONST_STRING: String 
CONST_OBJECT: xyz 

javap -c uscita:

 
Compiled from "ReflectionConstantTest.java" 
public class scratch.ReflectionConstantTest extends java.lang.Object{ 
public scratch.ReflectionConstantTest(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."":()V 
    4: return 

public static void main(java.lang.String[]) throws java.lang.Exception; 
    Code: 
    0: bipush 100 
    2: istore_1 
    3: ldc  #2; //String String 
    5: astore_2 
    6: getstatic  #3; //Field CONST_OBJECT:Ljava/lang/Object; 
    9: astore_3 
    10: ldc_w #4; //class scratch/ReflectionConstantTest 
    13: invokevirtual #5; //Method java/lang/Class.getDeclaredFields:()[Ljava/lang/reflect/Field; 
    16: astore 4 
    18: aload 4 
    20: arraylength 
    21: istore 5 
    23: iconst_0 
    24: istore 6 
    26: iload 6 
    28: iload 5 
    30: if_icmpge  90 
    33: aload 4 
    35: iload 6 
    37: aaload 
    38: astore 7 
    40: aload 7 
    42: iconst_1 
    43: invokevirtual #6; //Method java/lang/reflect/Field.setAccessible:(Z)V 
    46: getstatic  #7; //Field java/lang/System.out:Ljava/io/PrintStream; 
    49: new  #8; //class java/lang/StringBuilder 
    52: dup 
    53: invokespecial #9; //Method java/lang/StringBuilder."":()V 
    56: aload 7 
    58: invokevirtual #10; //Method java/lang/reflect/Field.getName:()Ljava/lang/String; 
    61: invokevirtual #11; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    64: ldc  #12; //String : 
    66: invokevirtual #11; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    69: aload 7 
    71: aconst_null 
    72: invokevirtual #13; //Method java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object; 
    75: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 
    78: invokevirtual #15; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    81: invokevirtual #16; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    84: iinc 6, 1 
    87: goto 26 
    90: return 

static {}; 
    Code: 
    0: new  #8; //class java/lang/StringBuilder 
    3: dup 
    4: ldc  #17; //String xyz 
    6: invokespecial #18; //Method java/lang/StringBuilder."":(Ljava/lang/String;)V 
    9: putstatic  #3; //Field CONST_OBJECT:Ljava/lang/Object; 
    12: return 

} 

Si può vedere che CONST_INT è inline, ma CONST_STRING e CONST_OBJECT (ovviamente) non sono. Eppure CONST_INT è ancora disponibile in modo riflessivo.

+0

Questo risolto il mio problema, grazie! Sono curioso di sapere perché dobbiamo chiamare f.setAccessible (true). Qual è il punto di avere modificatori statici non accessibili in primo luogo? – gsingh2011

+0

@ gsingh2011: l'unica ragione che è necessaria è dimostrare che è possibile accedere anche a costanti private tramite la reflection (si può osservare che le tre costanti nell'esempio sono dichiarate private). Le costanti pubbliche non dovrebbero essere impostate come accessibili, poiché sono già accessibili. –

+0

Ah, capisco. Mi sono appena reso conto che il mio problema si è verificato perché non ho fornito un modificatore pubblico/privato al mio campo e quindi ho rifattorizzato il mio codice in pacchetti. Grazie comunque per la risposta. – gsingh2011

1

Se open librerie di origine sono permessi sul progetto è possibile utilizzare

FieldUtils.readDeclaredStaticField

public class Test { 
    public final static String CONSTANT="myConstantValue"; 
} 

In un'altra classe si può utilizzare:

Object value = FieldUtils.readDeclaredStaticField(Test.class, "CONSTANT"); 
System.out.println(value); 

Nella console verrà visualizzato "myConstantValue".

0

Basta ottenere il nome e il valore non richiede setAccessible (vero). Ecco un esempio utile quando si ha a che fare con le costanti dichiarate in un'interfaccia, e desidera che i nomi simbolici:

interface Code { 
    public static final int FOO = 0; 
    public static final int BAR = 1; 
} 

... 

try { 
    for (Field field : Code.class.getDeclaredFields()) { 
     String name = field.getName(); 
     int value = field.getInt(null); 
     System.out.println(name + "=" + value); 
    } 
} 
catch (IllegalAccessException e) { 
    System.out.println(e); 
} 
Problemi correlati