繁体   English   中英

动态地知道类类型的对象的访问方法和函数

[英]Accessing Methods and functions of a object whose class type is dynamically known

我有一个类型A的对象A1。我动态地发现该对象A1的类型为A。我现在有一个属性“ Name”,我想从A1访问该属性,我该怎么做?

现在最大的问题是对象A1甚至可以是类型B。如果它是类型B,那么我将必须获得值“地址”。 现在我该如何解决?

下面的代码进行类型检查,


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

任何指针都会有很大帮助。 谢谢

您可以知道类的声明字段

 Class cls = Class.forName("MyClass");
 Field fieldlist[] = cls.getDeclaredFields();  

如果您手动进行操作,这种事情会很棘手且容易出错。 您应该使用几乎每个主要框架都包含的许多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 = class java.lang.String,foo = class java.lang.String}
baz:phleem
foo:bar

看这个: BeanUtils

myUser.setName("Bob");
// can instead be written:
BeanUtils.setProperty(myUser, "name", "Bob");
// and then retrieve:
BeanUtils.getProperty(myUser, "name");

这些字段通常是私有的。 因此,要访问它们,您必须致电

field.setAccessible(true);

顺便说一句,您确定您真的希望在这种情况下使用反射吗? 您可能考虑过声明接口吗? 该类(实现)仍可以动态加载。

例如: NameAccessorAddressAccessor是接口。

FirstClassSecondClass是类。 假设FirstClass实现NameAccessorSecondClass实现两个接口。

现在您可以说:

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

我认为(IMHO)这种解决方案比使用反射访问私有字段更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM