51

我需要使用反射调用一个类的setter方法,代码如下:

try {             
   Method method = myObj.getClass().getMethod("set" + fieldName, new Class[] { value.getClass() });               
   method.invoke(myObj, value);
     } catch (Exception ex) {
         ex.printStackTrace();
     }

valueis an和ArrayListsetter 方法如下:

public void setNames(List<String> names){
    this.names = names;
}

运行此代码时会抛出A java.lang.NoSuchMethodException,但是当将 setter 方法参数类型更改为ArrayListfrom时,List它可以正常执行。有没有办法在从类中获取方法时将setter方法参数保持在超类型并且仍然使用反射而不手动给出参数的类型?

4

7 回答 7

57

你可以使用BeanUtils

第1步

Customer customer = new Customer();

第2步

BeanUtils.setProperty(customer,"firstName","Paul Young");

您可以使用反射迭代所有类成员并相应地设置值,假设客户对象具有:

private String firstName;
// Getter and Setter are defined
于 2012-07-05T07:48:46.813 回答
55

如果您碰巧使用spring framework,您可以使用PropertyAccessorFactory来检索PropertyAccessor接口的实现:

直接访问属性

PropertyAccessor myAccessor = PropertyAccessorFactory.forDirectFieldAccess(object);
// set the property directly, bypassing the mutator (if any)
myAccessor.setPropertyValue("someProperty", "some value");

通过访问器/修改器访问属性

如果您需要使用它们的gettersetter访问您的属性,您可以使用以下forBeanPropertyAccess方法:

PropertyAccessor myAccessor = PropertyAccessorFactory.forBeanPropertyAccess(object);
// a `setSomeProperty()` method will be used
myAccessor.setPropertyValue("someProperty", "some value");
于 2013-04-12T13:46:10.260 回答
26

与其他答案相反,有一个非常简单的解决方案。见java.beans.Statement。它为您提供了一种执行任意反射代码的方法,而不必担心实际类型与正式类型(以及其他一些事情)。

于 2012-04-04T10:25:13.797 回答
4

有一个简单的解决方案,但这种简单是以性能为代价的。

我正在使用这个怪物:

public static Method findMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {

    // First try the trivial approach. This works usually, but not always.
    try {
        return clazz.getMethod(methodName, parameterTypes);
    } catch (NoSuchMethodException ex) {
    }

    // Then loop through all available methods, checking them one by one.
    for (Method method : clazz.getMethods()) {

        String name = method.getName();
        if (!methodName.equals(name)) { // The method must have right name.
            continue;
        }

        Class<?>[] acceptedParameterTypes = method.getParameterTypes();
        if (acceptedParameterTypes.length != parameterTypes.length) { // Must have right number of parameters.
            continue;
        }

        boolean match = true;
        for (int i = 0; i < acceptedParameterTypes.length; i++) { // All parameters must be right type.
            if (null != parameterTypes[i] && !acceptedParameterTypes[i].isAssignableFrom(parameterTypes[i])) {
                match = false;
                break;
            }
            if (null == parameterTypes[i] && acceptedParameterTypes[i].isPrimitive()) { // Accept null except for primitive fields.
                match = false;
                break;
            }
        }

        if (match) {
            return method;
        }

    }

    // None of our trials was successful!
    throw new NoSuchMethodException();
}

parameterTypes是你从你的value.getClass(). 它们中的一些或全部也可以为空。然后它们被视为任何非原始参数字段的匹配。

即使这样也不是完美的:如果有几个方法在多态上是合适的,但没有一个完全匹配,那么返回的方法是任意选择的(clazz.getMethods()返回数组中的第一个匹配项)。此行为不同于 Java 语言行为,其中始终使用“最接近的匹配”。

如果按名称获取方法就足够了(即,如果名称匹配,您假设参数是合适的),那么您可以更简单(并且更快)进行管理:

public static Method findMethod(Class<?> clazz, String methodName) {
  for (Method method : clazz.getMethods()) {
    if (method.getName().equals(methodName)) {
      return method;
    }
  }
  throw new NoSuchMethodException();
} 

为了进一步提高它,考虑某种缓存。

于 2012-04-04T10:18:26.863 回答
3

反射类有时被称为动态调用。

例如,让我们看看使用反射的 getter 方法

考虑有一个类被调用MyReflectionClass并且有一个方法被调用getreflect()。(例如类型字符串)让我们看看如何使用反射类

MyReflectionClass  obj = new MyReflectionClass();

<? extends MyReflectionClass> tempClass = obj.getClass();
String a = (String) obj.getMethod("getreflect").invoke(obj);

现在设置方法

(String) obj.getDeclaredMethod("setreflect", String.class).invoke(obj,"MyString");

如果您需要对字符串序列执行相同的操作,那么

    (String) obj.getDeclaredMethod("setreflect",
 new String.class{}).invoke(obj,"MyString1","MyString2");

希望它可能有用

于 2014-09-25T16:14:44.707 回答
1

示例 set 所有字段使用 setter 方法通过 ResultSet 获取值。

private Object setAllSetters(Object ob, ResultSet rs) throws SQLException{
    // MZ: Find the correct method
    Class cls = ob.getClass();
    while (rs.next()) {
        for (Field field : cls.getDeclaredFields()){
            for (Method method : cls.getMethods())
            {
                if ((method.getName().startsWith("set")) && (method.getName().length() == (field.getName().length() + 3)))
                {
                    if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
                    {
                        // MZ: Method found, run it
                        try
                        {
                            method.setAccessible(true);
                            if(field.getType().getSimpleName().toLowerCase().endsWith("integer"))
                                method.invoke(ob,rs.getInt(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("long"))
                                method.invoke(ob,rs.getLong(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("string"))
                                method.invoke(ob,rs.getString(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("boolean"))
                                method.invoke(ob,rs.getBoolean(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("timestamp"))
                                method.invoke(ob,rs.getTimestamp(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("date"))
                                method.invoke(ob,rs.getDate(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("double"))
                                method.invoke(ob,rs.getDouble(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("float"))
                                method.invoke(ob,rs.getFloat(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("time"))
                                method.invoke(ob,rs.getTime(field.getName().toLowerCase()));
                            else 
                                method.invoke(ob,rs.getObject(field.getName().toLowerCase()));
                        }
                        catch (IllegalAccessException | InvocationTargetException | SQLException e)
                        {
                            System.err.println(e.getMessage());
                        }
                    }
                }
            }
        }
    }
    return ob;
}
于 2013-08-06T17:34:14.903 回答
0

使用字符串处理检测方法名称可能看起来不像是正确的方法。将此视为解决方案之一。

    try {
            Animal animal = new Animal();
            BeanInfo beaninfo = Introspector.getBeanInfo(Animal.class);
            PropertyDescriptor pds[] = beaninfo.getPropertyDescriptors();
            Method setterMethod=null;
            for(PropertyDescriptor pd : pds) { 
                setterMethod = pd.getWriteMethod(); // For Setter Method

           /*
               You can get Various property of Classes you want. 
           */

                System.out.println(pd.getName().toString()+ "--> "+pd.getPropertyType().toString()+"--Setter Method:->"+pd.getWriteMethod().toString());

                if(setterMethod == null) continue;
                else
                    setterMethod.invoke(animal, "<value>");
            }
        }catch(Exception e) {e.printStackTrace();}
于 2016-06-16T06:45:55.977 回答