Java反射:我如何获得java类的所有getter方法并调用它们

use*_*505 70 java reflection

我写了一个有很多getter的java类..现在我想获取所有getter方法并在某个时候调用它们.我知道有一些方法,比如getMethods()或getMethod(String name,Class ... parameterTypes),但是我只是想得到吸气剂...,使用正则表达式?谁能告诉我?谢谢!

Sea*_*oyd 152

不要使用正则表达式,使用Introspector:

for(PropertyDescriptor propertyDescriptor : 
    Introspector.getBeanInfo(yourClass).getPropertyDescriptors()){

    // propertyEditor.getReadMethod() exposes the getter
    // btw, this may be null if you have a write-only property
    System.out.println(propertyDescriptor.getReadMethod());
}
Run Code Online (Sandbox Code Playgroud)

通常您不需要Object.class中的属性,因此您将使用具有两个参数的方法:

Introspector.getBeanInfo(yourClass, stopClass)
// usually with Object.class as 2nd param
// the first class is inclusive, the second exclusive
Run Code Online (Sandbox Code Playgroud)

顺便说一句:有一些框架可以帮助您,并为您提供高级视图.例如commons/beanutils有这个方法

Map<String, String> properties = BeanUtils.describe(yourObject);
Run Code Online (Sandbox Code Playgroud)

(docs here)就是这样做的:找到并执行所有的getter并将结果存储在map中.不幸的是,BeanUtils.describe()在返回之前将所有属性值转换为字符串.WTF.谢谢@danw


更新:

这是一个Map<String, Object>基于对象的bean属性返回的Java 8方法.

public static Map<String, Object> beanProperties(Object bean) {
  try {
    return Arrays.asList(
         Introspector.getBeanInfo(bean.getClass(), Object.class)
                     .getPropertyDescriptors()
      )
      .stream()
      // filter out properties with setters only
      .filter(pd -> Objects.nonNull(pd.getReadMethod()))
      .collect(Collectors.toMap(
        // bean property name
        PropertyDescriptor::getName,
        pd -> { // invoke method to get value
            try { 
                return pd.getReadMethod().invoke(bean);
            } catch (Exception e) {
                // replace this with better error handling
               return null;
            }
        }));
  } catch (IntrospectionException e) {
    // and this, too
    return Collections.emptyMap();
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,您可能希望使错误处理更加健壮.对于样板,很抱歉,检查异常会阻止我们在这里完全正常运行.


事实证明Collectors.toMap()讨厌空值.以下是上述代码的更为命令式版本:

public static Map<String, Object> beanProperties(Object bean) {
    try {
        Map<String, Object> map = new HashMap<>();
        Arrays.asList(Introspector.getBeanInfo(bean.getClass(), Object.class)
                                  .getPropertyDescriptors())
              .stream()
              // filter out properties with setters only
              .filter(pd -> Objects.nonNull(pd.getReadMethod()))
              .forEach(pd -> { // invoke method to get value
                  try {
                      Object value = pd.getReadMethod().invoke(bean);
                      if (value != null) {
                          map.put(pd.getName(), value);
                      }
                  } catch (Exception e) {
                      // add proper error handling here
                  }
              });
        return map;
    } catch (IntrospectionException e) {
        // and here, too
        return Collections.emptyMap();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用JavaSlang,以更简洁的方式使用相同的功能:

public static Map<String, Object> javaSlangBeanProperties(Object bean) {
    try {
        return Stream.of(Introspector.getBeanInfo(bean.getClass(), Object.class)
                                     .getPropertyDescriptors())
                     .filter(pd -> pd.getReadMethod() != null)
                     .toJavaMap(pd -> {
                         try {
                             return new Tuple2<>(
                                     pd.getName(),
                                     pd.getReadMethod().invoke(bean));
                         } catch (Exception e) {
                             throw new IllegalStateException();
                         }
                     });
    } catch (IntrospectionException e) {
        throw new IllegalStateException();

    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个番石榴版本:

public static Map<String, Object> guavaBeanProperties(Object bean) {
    Object NULL = new Object();
    try {
        return Maps.transformValues(
                Arrays.stream(
                        Introspector.getBeanInfo(bean.getClass(), Object.class)
                                    .getPropertyDescriptors())
                      .filter(pd -> Objects.nonNull(pd.getReadMethod()))
                      .collect(ImmutableMap::<String, Object>builder,
                               (builder, pd) -> {
                                   try {
                                       Object result = pd.getReadMethod()
                                                         .invoke(bean);
                                       builder.put(pd.getName(),
                                                   firstNonNull(result, NULL));
                                   } catch (Exception e) {
                                       throw propagate(e);
                                   }
                               },
                               (left, right) -> left.putAll(right.build()))
                      .build(), v -> v == NULL ? null : v);
    } catch (IntrospectionException e) {
        throw propagate(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 哇.我不知道你能做到的!凉! (6认同)
  • @RyanJ.McDonough 这是一个简单的 Java 问题,而不是 Android 问题。Introspector 是标准 Java 的标准机制。Android 可能有也可能没有不同的机制,但这并不会使我的答案无效 (2认同)

小智 20

您可以使用Reflections框架

import org.reflections.ReflectionUtils.*;
Set<Method> getters = ReflectionUtils.getAllMethods(someClass,
      ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("get"));
Run Code Online (Sandbox Code Playgroud)

  • 并非所有的getter都以"get"开头:(1)布尔返回的getter可以以"is"开头; (2)BeanInfo类可以声明其他方法是getter.你应该添加一个限制,如果你知道所有的getter都以"get"开头,你可以这样做. (5认同)

dku*_*mar 9

 // Get the Class object associated with this class.
    MyClass myClass= new MyClass ();
    Class objClass= myClass.getClass();

    // Get the public methods associated with this class.
    Method[] methods = objClass.getMethods();
    for (Method method:methods)
    {
        System.out.println("Public method found: " +  method.toString());
    }
Run Code Online (Sandbox Code Playgroud)

  • 是的,但是您还必须检查每个方法是否公开,非静态,返回void,不包含任何参数并遵循get / isXyz名称约定。Introspector会为您完成所有这些工作,另外还会在内部为其他应用程序缓存BeanInfo数据。 (2认同)

Ste*_*erl 8

Spring为Bean内省提供了一个简单的BeanUtil方法:

PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clazz, property);
Method getter = pd.getReadMethod();
Run Code Online (Sandbox Code Playgroud)