Ответ 1
В отличие от других ответов, существует очень простое решение. См. java.beans.Statement
. Это дает вам возможность выполнить произвольный отражающий код, не беспокоясь о фактических формальных типах (и нескольких других вещах).
Мне нужно вызвать методы setter класса с использованием отражения, а код выглядит следующим образом:
try {
Method method = myObj.getClass().getMethod("set" + fieldName, new Class[] { value.getClass() });
method.invoke(myObj, value);
} catch (Exception ex) {
ex.printStackTrace();
}
value
- это ArrayList
, а метод настройки:
public void setNames(List<String> names){
this.names = names;
}
A java.lang.NoSuchMethodException
вызывается при запуске этого кода, но когда тип параметра метода setter изменяется на ArrayList
из List
, он выполняет штраф. Есть ли способ сохранить параметр метода setter в супертипе и по-прежнему использовать отражение, не задавая вручную тип параметра при получении метода из класса?
В отличие от других ответов, существует очень простое решение. См. java.beans.Statement
. Это дает вам возможность выполнить произвольный отражающий код, не беспокоясь о фактических формальных типах (и нескольких других вещах).
Вы можете использовать BeanUtils:
Шаг # 1
Customer customer = new Customer();
Шаг # 2
BeanUtils.setProperty(customer,"firstName","Paul Young");
Вы можете выполнять итерацию всех членов класса с использованием отражения и устанавливать значения соответственно, предполагая, что объект-клиент имеет:
private String firstName;
// Getter and Setter are defined
Если вы используете фреймворк spring, вы можете использовать PropertyAccessorFactory для извлечения реализации PropertyAccessor интерфейс:
PropertyAccessor myAccessor = PropertyAccessorFactory.forDirectFieldAccess(object);
// set the property directly, bypassing the mutator (if any)
myAccessor.setPropertyValue("someProperty", "some value");
Если вам нужно получить доступ к своим ресурсам, используя их получатели и сеттеры, вы можете использовать вместо этого метод forBeanPropertyAccess
:
PropertyAccessor myAccessor = PropertyAccessorFactory.forBeanPropertyAccess(object);
// a `setSomeProperty()` method will be used
myAccessor.setPropertyValue("someProperty", "some value");
Существует простое решение, но эта простота идет за счет производительности.
Вместо этого я использую этот монстр:
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 Language, в котором всегда используется "самое близкое совпадение".
Если получить метод по имени достаточно (т.е. вы предполагаете, что параметры подходят, если имя совпадает), то вы можете управлять гораздо проще (и несколько быстрее):
public static Method findMethod(Class<?> clazz, String methodName) {
for (Method method : clazz.getMethods()) {
if (method.getName().equals(methodName)) {
return method;
}
}
throw new NoSuchMethodException();
}
Чтобы еще больше увеличить его, рассмотрите какой-то кеш.
Пример set Все filds, используя методы seters, получая значения с помощью 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;
}
Класс отражения иногда называют динамическим вызовом.
например, давайте рассмотрим методы геттера с использованием отражения
считают, что существует класс под названием MyReflectionClass
и имеет метод под названием getreflect()
. (например, строка типа)
позволяет увидеть, как использовать классы отражения
MyReflectionClass obj = new MyReflectionClass();
<? extends MyReflectionClass> tempClass = obj.getClass();
String a = (String) obj.getMethod("getreflect").invoke(obj);
теперь метод setter
(String) obj.getDeclaredMethod("setreflect", String.class).invoke(obj,"MyString");
если вам нужно выполнить ту же операцию с последовательностью строки, затем
(String) obj.getDeclaredMethod("setreflect",
new String.class{}).invoke(obj,"MyString1","MyString2");
надеюсь, что это может быть полезно
Обнаружение имен методов с использованием 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();}