Вопрос по java, reflection – Вызов метода установки с использованием отражения Java

32

Мне нужно вызвать методы установки класса, используя отражение, и код, как показано ниже:

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

value являетсяArrayList и метод установки, как показано ниже:

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

java.lang.NoSuchMethodException генерируется при запуске этого кода, но когда тип параметра метода установки изменяется наArrayList отList это работает хорошо. Есть ли способ сохранить параметр метода set в супертипе и при этом использовать отражение без указания типа параметра вручную при получении метода из класса?

Ваш Ответ

7   ответов
1

Пример set Все поля, использующие методы setters, получают значения с помощью 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;
}
19

Вопреки другим ответам, есть действительно простое решение. Увидетьjava.beans.Statement, Это дает вам возможность выполнить произвольный рефлексивный код, не беспокоясь о реальных или формальных типах (и некоторых других вещах).

@JoonasPulakka Это медленно, потому что он делает все, что вам нужно сделать, чтобы решить эту проблему. Разрешение фактических типов аргументов к формальным типам-параматорам равно O (M ** N), если M - это число параметров, а N - длина их цепочки наследования типов.
Спасибо @JoonasPulakka. Я бы предпочел простоту, а не производительность, так как это пока еще не огромный эффект. Dilini Rajapaksha
Глядя на источникиjava.beans.Statementего медлительность объясняется тем, что он обрабатывает все эти детали, такие как модификаторы доступа, наиболее специфическое полиморфное совпадение и т. д. Это компромисс - хотите ли вы простоты за счет производительности или производительности за счет принятия некоторых предположений (которые, если не правильно, может быть опасно).
Спасибо за простое решение, я попробовал, и он отлично работает. Я не знал об этомjava.beans.Statement класс и сделал некоторые ссылки. Очень трудно найти много статей на эту тему, кроме документации по API. Вthis статья сравнивает с API отражения и говорит, что это медленно. Есть ли какая-то причина, почему он не так популярен, как API отражения? Dilini Rajapaksha
3

Eстьпростое решениеНо эта простота достигается за счет производительности.

Вместо этого я использую этого монстра:

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();
} 

Чтобы еще больше увеличить его, рассмотрим какой-то кеш.

«Поставляется за счет».what спектакль? Что именно делает Statement, делает это, что не делает?
43

Если вам случится использоватьspring frameworkВы могли бы использоватьPropertyAccessorFactory для получения реализацииPropertyAccessor интерфейс:

Accessing properties directly

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

Accessing properties through accessors/mutators

Если вам нужно получить доступ к вашим свойствам, используя ихgetters а такжеsettersВы можете использовать вместоforBeanPropertyAccess метод:

PropertyAccessor myAccessor = PropertyAccessorFactory.forBeanPropertyAccess(object);
// a `setSomeProperty()` method will be used
myAccessor.setPropertyValue("someProperty", "some value");
Здорово, когда вы используете Spring. Это мне очень помогает.
спас мой день !!!!
0

Класс Reflection иногда называют динамическим вызовом.

например, давайте посмотрим на методы получения, используя отражение

считают, что есть класс под названием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");

надеюсь, что это может быть полезно

0

Обнаружение имен методов с использованием String Handling может не выглядеть как правильный способ сделать это. Считайте это одним из решений.

    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();}
импорт java.beans.BeanInfo; импорт java.beans.Introspector; import java.beans.PropertyDescriptor;
Пакет java.beans выглядит совершенно новым для меня, я сделаю несколько R & D в том же ... это может быть интересно :)
Что такоеIntrospector? это сторонний API? Dilini Rajapaksha
48

Вы могли бы использоватьBeanUtils:

Step #1

Customer customer = new Customer();

Step #2

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

Вы можете перебрать все члены класса, используя отражение и установить значения соответственно, предполагая, что объект customer имеет:

private String firstName;
// Getter and Setter are defined

Похожие вопросы