【问题标题】:See if field exists in class查看类中是否存在字段
【发布时间】:2017-10-28 19:47:33
【问题描述】:

我有一个包含各种变量的类

public class myClass{

    public int id;
    public String category;
    public String description;
    public String start;
    public String end;
}

有没有办法通过创建内部函数或从调用对象检查变量是否存在?

例如检查 myClass 是否包含名为“category”的变量(确实如此)。或者它是否包含一个名为“foo”的类别(它没有)。

【问题讨论】:

  • 有没有办法调用同一个字段的setter方法???

标签: java


【解决方案1】:

警告:接受的答案会起作用,但它依赖于异常作为控制流,即bad practice,应尽可能避免。

请考虑以下替代方案:

public boolean doesObjectContainField(Object object, String fieldName) {
    Class<?> objectClass = object.getClass();
    for (Field field : objectClass.getFields()) {
        if (field.getName().equals(fieldName)) {
            return true;
        }
    }
    return false;
}

或者使用 Java 8 流的更简洁的形式:

public boolean doesObjectContainField(Object object, String fieldName) {
    return Arrays.stream(object.getClass().getFields())
            .anyMatch(f -> f.getName().equals(fieldName));
}

这些代码 sn-ps 不依赖异常作为控制流,实际上根本不需要任何异常处理,这将使您的实现更简单,更具可读性。您只需使用类似于以下的代码调用上述方法之一:

Object someObject = ... ;
boolean fieldExists = doesObjectContainField(someObject, "foo");

附带说明,如果您需要访问类的私有字段(而不是父类字段),您可以简单地将对 getFields 的调用替换为 getDeclaredFields

【讨论】:

  • 好点!由于我曾经在生产环境中遇到过由“异常作为控制流”引起的性能问题,因此我绝不会建议任何人容忍“作为控制流的异常”
  • @Pyves--感谢提供方法。但是,我无法编译它:“java.lang.NullPointerException at Utilities.Utilities.objectContainsField(Utilities.java:25) at search.GUI.initComponents(GUI.java:280)”第 25 行是 @987654327 @objectClass 定义的一部分。仅供参考:我打算像这样使用您的方法:if(Utilities.objectContainsField(a_testing,"dateFrom"))...do something 其中a_testingClass A_testing 的实例,其中包含字段dateFrom。 (由于您的答案已有 2 年历史,因此我不希望对此做出回应,因此我可能会开始新线程。)
  • @DSlomer64 你确定你传入的a_testing 对象不是null
  • @Pyves——我终于得到了“简洁”的版本来编译!很久以前,当前两个版本出错或无法编译时,我放弃了,但今天我又重击了一次,显然取得了成功。顺便说一句,AFAICT a_testing 不是空的。当然不是今天,
【解决方案2】:

您的编译器通常很清楚这一点,运行时允许您使用反射检查加载的类。

Object someObject = ...
Class<?> someClass = someObject.getClass();
Field someField = someClass.getField("foo");

如果找不到该字段,getField() 方法将抛出异常。

【讨论】:

  • 如果无法访问则返回 SecurityException(例如 private
  • @CrackerJack9 不,使用getField() 访问私有字段不会抛出SecurityException
  • @Bombe 我没有测试它,但docs.oracle.com/javase/7/docs/api/java/lang/… 说它会抛出一个SecurityException“...如果满足这些条件中的任何一个”:调用s.checkMemberAccess(this, Member.PUBLIC) 拒绝访问字段`
  • @CrackerJack9 true,但这与字段是否为private 无关,也与拒绝访问的SecurityManager 有关。
  • @Bombe 因此使用例如
【解决方案3】:

正如其他人已经提到的,反射是您所需要的。

如果您需要访问私有字段,您可以使用 Class.getDeclaredField(String name)

【讨论】:

    【解决方案4】:

    您可以使用reflection 进行操作,但我建议您检查是否真的需要它,或者是否有其他方法。

    例如:

    Class<?> clz = MyClass.class;
    try {
        Field f = clz.getField("foo")
    }
    catch ( NoSuchFieldException ex) {
        // field doesn't exist
    }
    catch (SecurityException ex) {
        // no access to field
    }
    

    【讨论】:

      【解决方案5】:

      您正在寻找的东西称为“反射”。它提供了在运行时确定类中包含哪些字段和方法的能力。

      http://today.java.net/pub/a/today/2008/02/12/reflection-in-action.html

      【讨论】:

      • 链接已损坏。
      【解决方案6】:

      单步执行有点不方便。

      当我们转向多态概念时,会遇到一些挑战,例如通过引用其他包含相同字段但静态和最终类型的专用类(ABCXMLDOMnodes 类、ABCHTMLDOMnodes 类)来动态获取数据的类(ABC 类)缺少对象。希望你能满足要求。

      1.创建字段的ArrayList 这三个类的简单名称为全局。

       private static ArrayList<String> getAllFieldsSimpleNames(Class<?> beanClass) {
          ArrayList<String> fieldNames = new ArrayList<String>();
          Field[] fields = beanClass.getDeclaredFields();
          for (Field field : fields) {
              fieldNames.add(field.getName());
          }
          return fieldNames;
      }
      

      2.然后每次生成一个对象时,我们都会针对下面的帮助类验证字段(比如 >10 个字段),我觉得很容易。

       for(String a :abcFieldNames){
              if(abcXMLfieldnames.contains(a)){
              //code here
              }else if(abcHTMLfieldnames.contains(a){
              //code here
              }
          }
      

      其他最简单和动态的方式是创建

            HashMap<Class<?>, ArrayList<String>> = ...
          hm.put(ABC.class, getAllFieldsSimpleNames(ABC.class));
          hm.put(ABCXMLDOMnodes.class, getAllFieldsSimpleNames(ABCXMLDOMnodes.class));
      if(hm.get(ABCXMLDOMnodes.class).contains("a"){...}
      

      我对 Oracle Corp. JAVA 网络的建议是,如果“Class class”可以提供一种方法,该方法仅将给定 Class 的字段名称列表作为字符串类型返回会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-09
        • 1970-01-01
        • 1970-01-01
        • 2014-05-18
        • 1970-01-01
        • 2019-03-04
        相关资源
        最近更新 更多