2009-05-11 9 views

Répondre

55

Je suppose que cela dépend du type et le compilateur (à la réflexion, il vaut mieux ne pas!). Le compilateur de Sun intègre les constantes primitives, mais je ne sais pas si elles suppriment entièrement l'entrée de la classe. Je trouverai.

Editer: Oui, vous pouvez toujours y accéder même s'ils sont en ligne. Classe d'essai:

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)); 
     } 
    } 
} 

Sortie:

 
CONST_INT: 100 
CONST_STRING: String 
CONST_OBJECT: xyz 

javap -c sortie:

 
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 

} 

Vous pouvez voir que CONST_INT est inline, mais CONST_STRING et CONST_OBJECT (bien sûr) ne sont pas. Pourtant, CONST_INT est toujours disponible de manière réfléchie.

+0

Cela a résolu mon problème, merci! Je suis curieux de savoir pourquoi nous devons appeler f.setAccessible (true). Quel est le point d'avoir des modificateurs statiques pas accessible en premier lieu? – gsingh2011

+0

@ gsingh2011: La seule raison qui est nécessaire est de démontrer que même les constantes privées peuvent être accédées par réflexion (vous pouvez observer que les trois constantes de l'exemple sont déclarées privées). Les constantes publiques n'auraient pas besoin d'être accessibles, puisqu'elles sont déjà accessibles. –

+0

Ahh, je vois. Je viens de réaliser que mon problème est survenu parce que je n'ai pas fourni de modificateur public/privé à mon champ, et que j'ai ensuite refactorisé mon code en paquets. Merci quand même pour la réponse. – gsingh2011

1

Si ouvert bibliothèques sources sont autorisées sur votre projet, vous pouvez utiliser

FieldUtils.readDeclaredStaticField

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

Dans une autre classe, vous pouvez utiliser:

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

Vous verrez "myConstantValue" dans la console.

0

Obtenir simplement le nom et la valeur ne nécessite pas setAccessible (true). Voici un exemple utile lorsque vous devez traiter des constantes déclarées dans une interface, et que vous voulez les noms symboliques:

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); 
} 
Questions connexes