简体   繁体   中英

Using a String to find a static variable Java

I need to find a way to use a String, to get the value of a variable, in a another class. For instance, say I had this class:

public class ClassName {
   public static File f = new File ("C:\\");
}

And I also had this String in a different class:

String str = "ClassName.f";

Is there a way I could use the String, str, to get the value of ClassName.f? I don't want to have to hard code each value into a specific method.

Assuming you always only want static fields, the following code does some string splitting and uses reflection to do this. It will print "oy" when run...

import java.lang.reflect.Field;

public class StackOverflow {

    public static String oy = "OY";

    public static void main(String[] args) {
        System.out.println(getStaticValue("StackOverflow.oy"));
    }

    public static Object getStaticValue(String fieldId) {
        int idx = fieldId.indexOf(".");
        String className = fieldId.substring(0, idx);
        String fieldName = fieldId.substring(idx + 1);

        try {
            Class<?> clazz = Class.forName(className);
            Field field = clazz.getDeclaredField(fieldName);
            return field.get(null);
        } catch(Exception ex) {
           // BOOM!
            ex.printStackTrace();
        }

        return null;
    }
}

If your static field is not public, you will need to make it accessible, to do this, you need to add the "setAccessible" line...

import java.lang.reflect.Field;

public class StackOverflow {

    private static String oy = "OY";

    public static void main(String[] args) {
        System.out.println(getStaticValue("StackOverflow.oy"));
    }

    public static Object getStaticValue(String fieldId) {
        int idx = fieldId.indexOf(".");
        String className = fieldId.substring(0, idx);
        String fieldName = fieldId.substring(idx + 1);

        try {
            Class<?> clazz = Class.forName(className);
            Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(null);
        } catch(Exception ex) {
           // BOOM!
            ex.printStackTrace();
        }

        return null;
    }
}

Use reflection :

// make array to use easier
String[] str = "ClassName.f".split("\\.");

// get the class
Class c = Class.forName("packagename." + str[0]);
// get the field
Field field = c.getDeclaredField(str[1]);

// USE IT!
System.out.println(field.getName());

OUTPUT:

f

A map, as suggested in the comments, could be your best bet, as in this case reflection might not be the best practice.

To be able to call it from anywhere in your program, you'd need something like the Singleton pattern, which has to be handled with care:

public class ClassNameHandler {
   private static ClassNameHandler instance = null;
   protected ClassNameHandler() {
      // Exists only to defeat instantiation.
   }

   public Map<String, File> map = new HashMap<String, File>();

   public File f = ClassName.f;
   map.put("ClassName.f", f);
   //Add more files or variables to the map

   public static ClassNameHandler getInstance() {
      if(instance == null) {
         instance = new ClassNameHandler();
      }
      return instance;
   }
}

Then, elsewhere, you could use something like :

String str = "ClassName.f";
ClassNameHandler.map.get(str);

Double check the singleton pattern for implementation. If it sounds like too much, then there may be other options available but you did not provide much context or what the purpose of your application is, so it depends.

I needed something like this as part of injecting api keys into Unity3d via Android apps

Thanks to some of the answers here I came up with:

inside OnCreate

tryPutExtra("SECRET_API_STUFF");

tryPutExtra function

void tryPutExtra(String prop) {
    try {
        Field field = BuildConfig.class.getDeclaredField(prop);
        String str = String.valueOf(field);
        getIntent().putExtra(prop, str);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
}

** EDIT **

At some point the the above function stopped working and I don't know why. I've migrated to the following:

    try {
        Field field = BuildConfig.class.getDeclaredField(prop);
        // String str = String.valueOf(field);
        String str = field.get(null).toString();
        intent.putExtra(prop, str);
        Log.i(null, "PutExtra " + prop + " = " + str);
        field.setAccessible(true);
    } catch (Exception e) {
        e.printStackTrace();
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM