【问题标题】:How to access class fields of a class that I only know it by its string name?如何访问我只通过字符串名称知道的类的类字段?
【发布时间】:2010-03-02 21:40:50
【问题描述】:

例如,我有一个名为“My_Class_X123.java”的类,如下所示:

public class My_Class_X123    // This file was generated by a java program
{
  static String ABC[]={"1","2",...};
  int XYZ=0;
}

当我写我的程序时,我不知道会有这个名字的类,但在运行时我发现一个名为“My_Class_X123.java”的类存在,我想使用它的字段,例如上面的 ABC 和 XYZ,如何得到这些值?


好的,我得到了答案,是这样的:

  try
  {
    Class myClass=Class.forName("My_Class_X123");
    Field fields[]=myClass.getDeclaredFields();
    String New_ABC[]=String[].class.cast(fields[0].get(String[].class));
  }
  catch (Exception e) { e.printStackTrace(); }

如果在 java 文档中有一些这样的示例代码,向用户展示如何做,那不是很好吗!

弗兰克

【问题讨论】:

    标签: java reflection class field classloader


    【解决方案1】:

    您需要使用Reflection。不久前,我 wrote 一些 JSTL 标记实用程序可以执行此类操作。一个函数检查一个类是否是传入字符串的实例(基本上是instanceof)。另一个检查一个类是否具有指定的属性 (hasProperty)。以下代码 sn-p 应该会有所帮助:

    //Checks to see if Object 'o' is an instance of the class in the string "className"
    public static boolean instanceOf(Object o, String className) {
        boolean returnValue;
    
        try {
            returnValue = Class.forName(className).isInstance(o);
        }
    
        catch(ClassNotFoundException e) {
            returnValue = false;
        }
    
        return returnValue;
    }
    
    //Checks to see if Object 'o' has a property specified in "propertyName"
    public static boolean hasProperty(Object o, String propertyName) {
        boolean methodFound = false;
        int i = 0;
    
        Class myClass = o.getClass();
        String methodName = "get" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
        Method[] methods = myClass.getMethods();
    
        while(i < methods.length && !methodFound) {
            methodFound = methods[i].getName().compareTo(methodName) == 0;
            i++;
        }
    
        return methodFound;
    }
    

    特别注意第一个方法(加载和初始化一个类)中的Class.forName 方法和第二个函数中的getMethods() 方法,它返回为一个类定义的所有方法。

    你可能想要的是Class.forName,它也初始化了这个类。之后,您可以使用newInstance 获取该类的新实例(如果需要)。要访问这些字段,您需要使用从getMethod() 获得的Method 对象。对这些对象使用invoke 方法。如果这些方法是 getter 方法,那么您现在可以访问所需的字段。

    编辑

    查看您问题中的代码后,我意识到您需要这些属性的 getter 和 setter。因此,假设您定义了 getABCgetXYZ,这里有一个有些人为的例子:

    public Object reflectionDemo(String className, String getter) throws ClassNotFoundException, NoSuchMethodException {
    
       Object fieldValue;
       Class myClass = Class.forName(className);
       Object myClassInstance = myClass.newInstance(); //to get an instance of the class       
    
       if(myClassInstance instanceof My_Class_X123) {       
          //null because we are not specifying the kind of arguments that class takes
          Method getterMethod = myClass.getMethod(getter, null); 
          //null because the method takes no arguments
          //Also in the scenario that the method is static one, it is not necessary to pass in an instance, so in that case, the first parameter can be null.
          fieldValue = getterMethod.invoke(myClassInstance, null);
       } 
    
       return fieldValue;
    }
    

    上述方法更通用。如果您只想要这些字段,那么您可以使用 James 描述的方法:

    myClass = null;
    try {
      myClass = Class.forName(className);
      Field[] fields = myClass.getDeclaredFields();
    
      for(Field field : fields) {
        //do whatever with the field. Look at the API reference at http://java.sun.com/javase/6/docs/api/java/lang/reflect/Field.html    
      }
    }
    
    catch(Exception e) {
      //handle exception
    }
    

    【讨论】:

    • 但是如何先获取“o”对象呢?
    • 在编程时我不知道类的名称,所以这一行不起作用:“if(myClassInstance instanceof My_Class_X123)”
    • 糟糕,我的错。在这种情况下,您实际上所能做的就是取出instanceof 并尝试获取具有指定名称的方法。如果该方法不存在,这将抛出一个NoSuchMethodException,因此您需要一个try...catch 块。
    【解决方案2】:

    如果只需要类字段甚至不需要创建实例,只要使用反射获取Class就可以使用getDeclaredFields()方法获取字段名称及其值,例如

    Class myClass = null;
    
    try {
        myClass = Class.forName("package.ClassName");
        Field[] fields = myClass.getDeclaredFields();
    
        for (Field field : fields) {
             System.out.println("Field type is: " + field.getType());
             System.out.println("Field name is: " + field.getName());
        }
    } catch (Exception e) {
    }
    

    【讨论】:

    • 哦,太好了!不知何故,我滑倒了 :) 我有一个问题,为什么你有在你的 catch 块中获取声明字段的代码? myClass 不会是 null 吗?
    • 我确实需要使用字段中的值,而不仅仅是它们的名称。
    • 好的,那么如何从示例代码的 ABC[] 中获取值 "1","2" ...?
    • Frank,查看 Field 对象的 Java API 文档。
    • 是的,我有,但仍然无法弄清楚如何,如果它在文档中有示例用法会很好,我现在能想到的是这样的:if (field. getName().equals("ABC")) { String ABC_New[]=(String[])field; ...然后使用 ABC_New[] ... } 但它不起作用,正确的方法是什么?
    【解决方案3】:

    使用 java.lang.reflect。先用ClassLoader获取类的Class,然后调用newInstance获取对象,再使用反射接口获取字段。

    综合教程直播here

    【讨论】:

      猜你喜欢
      • 2022-07-22
      • 2023-03-17
      • 2016-01-31
      • 1970-01-01
      • 2016-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多