Доступ к методам и функциям объекта, тип класса которого известен динамически - PullRequest
1 голос
/ 25 октября 2010

У меня есть объект A1 типа A. Я динамически обнаруживаю, что объект A1 имеет тип A. Теперь у меня есть свойство сказать «Имя», к которому я хочу получить доступ из A1, как мне это сделать?

Теперь самая большая проблема в том, что объект A1 может даже иметь тип B. Если он имеет тип B, тогда мне нужно будет получить значение «Address». Теперь, как мне решить эту проблему?

Ниже код проверяет тип,


public static void testing(Object A1, String s) s - Classtype
  {
      try{
          Class c = Class.forName(s);

          if( c.isInstance(A1)) // 
          {
              //Now I know that A1 is of the  type C. But I dont know what type 'c' is (whether type A or type B. Because Only then I can access the appropriate member.) Like I said, type A contain 'name' and type B contains address.
              // The access may not only be a member but also a method .
          }
      }catch (Exception e){ System.out.println(e);}
  }

Любые указатели очень помогли бы. спасибо

Ответы [ 4 ]

3 голосов
/ 25 октября 2010

Вы можете знать объявленные поля класса

 Class cls = Class.forName("MyClass");
 Field fieldlist[] = cls.getDeclaredFields();  
1 голос
/ 26 октября 2010

Посмотрите на это: BeanUtils

myUser.setName("Bob");
// can instead be written:
BeanUtils.setProperty(myUser, "name", "Bob");
// and then retrieve:
BeanUtils.getProperty(myUser, "name");
1 голос
/ 25 октября 2010

Такие вещи сложны и подвержены ошибкам, если вы делаете это вручную. Вы должны использовать один из многих классов BeanUtils / BeanHelper, которые содержатся почти в каждой основной среде. Вот мой быстрый пример реализации, который вы можете использовать, если хотите:

public final class BeanHelper{

    /**
     * Return a map of an object's properties (key: property name, value:
     * property type).
     * 
     * @exception NullPointerException
     *                if bean is null
     */
    public static Map<String, Class<?>> describeProperties(final Object bean){
        if(bean == null){
            throw new NullPointerException();
        }
        final Map<String, Class<?>> map;
        final Class<?> beanClass = bean.getClass();
        if(PROPERTIES_CACHE.containsKey(beanClass)){
            map = PROPERTIES_CACHE.get(beanClass);
        } else{
            final PropertyDescriptor[] propertyDescriptors =
                getBeanInfo(beanClass);
            if(propertyDescriptors.length == 0){
                map = Collections.emptyMap();
            } else{
                final Map<String, Class<?>> innerMap =
                    new TreeMap<String, Class<?>>();
                for(final PropertyDescriptor pd : propertyDescriptors){
                    innerMap.put(pd.getName(), pd.getPropertyType());
                }
                map = Collections.unmodifiableMap(innerMap);
            }
            PROPERTIES_CACHE.put(beanClass, map);
        }
        return map;
    }

    private static PropertyDescriptor[] getBeanInfo(final Class<?> beanClass){
        try{
            return Introspector.getBeanInfo(beanClass, Object.class)
                .getPropertyDescriptors();
        } catch(final IntrospectionException e){
            throw new IllegalStateException(
                MessageFormat.format(
                "Couldn''t access bean properties for class {0}",
                beanClass),
                e);
        }
    }

    /**
     * Retrieve a named property from a specified object.
     * 
     * @return the property
     * @exception NullPointerException
     *                if one of the arguments is null
     * @exception IllegalArgumentException
     *                if there is no such property
     */
    public static Object getBeanProperty(final Object bean,
        final String property){
        if(bean == null || property == null){
            throw new NullPointerException();
        }
        final Class<?> beanClass = bean.getClass();
        Map<String, PropertyDescriptor> propMap;
        if(PROPERTY_DESCRIPTOR_CACHE.containsKey(beanClass)){
            propMap = PROPERTY_DESCRIPTOR_CACHE.get(beanClass);
        } else{
            final PropertyDescriptor[] beanInfo = getBeanInfo(beanClass);
            if(beanInfo.length == 0){
                propMap = Collections.emptyMap();
            } else{
                propMap =
                    new HashMap<String, PropertyDescriptor>(beanInfo.length);
                for(final PropertyDescriptor pd : beanInfo){
                    propMap.put(pd.getName(), pd);
                }
            }
            PROPERTY_DESCRIPTOR_CACHE.put(beanClass, propMap);
        }
        if(!propMap.containsKey(property)){
            throw new IllegalArgumentException(
                MessageFormat.format(
                "Class {0} does not have a property ''{1}''",
                beanClass,
                property));
        }
        return invokeMethod(propMap.get(property).getReadMethod(), bean);

    }

    private static Object invokeMethod(final Method method,
        final Object bean,
        final Object... args){
        try{
            return method.invoke(bean, args);
        } catch(final IllegalArgumentException e){
            throw e;
        } catch(final IllegalAccessException e){
            throw new IllegalStateException(
                MessageFormat.format(
                "Method not accessible: {0}",
                method),
                e);
        } catch(final InvocationTargetException e){
            throw new IllegalStateException(
                MessageFormat.format(
                "Error in method: {0}",
                method),
                e);
        }
    }

    private static final Map<Class<?>, Map<String, Class<?>>>
        PROPERTIES_CACHE =
        new ConcurrentHashMap<Class<?>, Map<String, Class<?>>>();

    private static final Map<Class<?>, Map<String, PropertyDescriptor>>
        PROPERTY_DESCRIPTOR_CACHE =
        new ConcurrentHashMap<Class<?>, Map<String, PropertyDescriptor>>();

    private BeanHelper(){
    }

}

Код теста:

public static void main(final String[] args){
    class Dummy{
        private String foo = "bar";
        private String baz = "phleem";
        public String getFoo(){
            return foo;
        }
        public void setFoo(final String foo){
            this.foo = foo;
        }
        public String getBaz(){
            return baz;
        }
        public void setBaz(final String baz){
            this.baz = baz;
        }
    }
    final Object dummy = new Dummy();
    final Map<String, Class<?>> beanProperties =
        BeanHelper.describeProperties(dummy);
    System.out.println(beanProperties);
    for(final String key : beanProperties.keySet()){
        System.out.println(MessageFormat.format("{0}:{1}",
            key,
            BeanHelper.getBeanProperty(dummy, key)));
    }
}

Выход:

{baz = класс java.lang.String, foo = класс java.lang.String}
Баз: phleem
Foo: бар

0 голосов
/ 25 октября 2010

Поля обычно являются частными. Итак, чтобы получить к ним доступ, нужно позвонить

field.setAccessible(true);

Кстати, вы уверены, что действительно хотите использовать отражение в этом случае? Вы, наверное, думали об объявлении интерфейса? Класс (реализация) все еще может быть загружен динамически.

Например: NameAccessor и AddressAccessor являются интерфейсами.

FirstClass и SecondClass являются классами. Предположим, что FirstClass реализует NameAccessor, а SecondClass реализует оба интерфейса.

Теперь вы можете сказать:

Class clazz = Class.forName("SecondClass");
Object obj = clazz.newInstance();
//......
String name = ((NameAccessor)obj).getName();
String address = ((AddressAccessor)obj).getAddress();

Я думаю (ИМХО), что это решение лучше, чем доступ к закрытым полям с помощью отражения.

...