【问题标题】:get associated getter/setter of field (member variable)获取相关的 getter/setter 字段(成员变量)
【发布时间】:2018-08-14 09:12:33
【问题描述】:

我有一个 Field f 某个类 MyClass 并且我想检索关联的 getter/setter(如果存在)。我该怎么做?

  • 我检查了Field的方法,但没有一个返回Method
  • 我玩过BeanInfo 检索到的Introspector.getBeanInfo(Class<?> beanClass)。它有一个方法getPropertyDescriptors(),它返回一个PropertyDescriptor 的数组,每个PropertyDescriptor 允许通过getReadMethod()getWriteMethod() 检索getter 和setter。但似乎与Field 没有任何联系。此外,似乎不可能获得某个PropertyDescriptor(例如,通过将字段名称作为参数进行检索);所以即使有办法从PropertyDescriptor 获取Field,我也需要遍历所有PropertyDescriptors。这不是高性能的。

注意:我不想依赖命名约定,所以请不要给出摆弄字段名称的答案。毕竟,没有名称 getMyFieldisMyField 的字段 myField 的吸气剂仍然是吸气剂。

【问题讨论】:

  • 字段的 getter 是基于 命名约定(标准或规范或任何可以调用的,JavaBeans 在这种特定情况下只是一个约定)。即使您有提供直接field -> getter 链接的工具,它也只是名称周围的快捷方式
  • 我非常怀疑您是否可以在不依赖命名约定的情况下做到这一点(毕竟,这是我们知道它们是给定字段的 getter/setter 的唯一方法)。您必须自省类中每个方法的代码,接受该字段类型的单个参数或返回该类型。即便如此,你怎么知道他们只是设置者/获取者而不是有其他目的?毕竟,验证代码(在 setter 中)或延迟初始化代码(在 getter 中)看起来很像做其他事情的代码......
  • 这个想法是,getter 和 setter 可能不直接对应于实际字段,它们可能是在其他地方派生、计算或存储的。换句话说,不一定有直接的对应关系,所以 Java 没有任何东西。

标签: java reflection field getter-setter member-variables


【解决方案1】:

这是我的想法,但并不完全正确。 检查方法名称中是否包含字段名称,以及返回类型和参数参数类型。我觉得如果没有关于字段的 setter/getter 方法的规则。这几乎是不可能的。

    @Test
    void test_fieldGetterSetter() throws NoSuchFieldException {
    Field f = MyClass.class.getDeclaredField("name");
    Class<?> declaringClass = f.getDeclaringClass();

    Method[] declaredMethods = declaringClass.getDeclaredMethods();

    for (Method declaredMethod : declaredMethods) {
        String name = declaredMethod.getName();

        // Can also check return type, argument type to increase the correctness
        if (isFieldNameWithMethodName(f.getName(), name)) {
            String format = String.format("Field name is %s and possible method name is %s", f.getName(), name);
            System.out.println(format);
        }
    }
}

private boolean isFieldNameWithMethodName(String fieldName, String methodName) {
    if (methodName.toLowerCase().contains(fieldName.toLowerCase())) {
        return true;
    }

    return false;
}

【讨论】:

    【解决方案2】:

    事实证明,在 Java 中,getter/setter 不仅由它们的签名和行为(如我所想)定义,而且还通过遵循命名约定来定义。

    所以为了获得对象Field myField 的对象myObject 的getter/setter,我们需要创建其对应的getter/setter 方法名称methodName(使用Field.getName() 然后摆弄@987654326 @/set 和 camelCase),然后致电 myObject.getClass().getMethod(methodName, ...)。参数(...) 可以使用Field.getType() 检索,并且必须根据我想要getter 还是setter 不同。

    证明命名很重要: 对于这个类

    public class ClassWithUnconventionalNaming {
    
        private int foo;
        public int myGetter() { return foo; }
        public void mySetter(int x) { this.foo = x; }
        public void setBaz(boolean x) { this.foo = 2; };
    
        private String bar;
        public String getBar() { return "hello world"; }
        public void setBar(String bar) { this.bar = bar; }
    
        private boolean baz;
        public boolean isBaz() { return baz; }
    }
    

    我运行了代码

    ClassWithUnconventionalNaming myClass = new ClassWithUnconventionalNaming();
    myClass.mySetter(5);
    
    BeanInfo info = Introspector.getBeanInfo(ClassWithUnconventionalNaming.class);
    for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
        String propertyName = pd.getName();
        System.out.println("property name: " + propertyName);
        Method getter = pd.getReadMethod();
        System.out.println("    getter: " + ((getter == null) ? "" : getter.getName()));
        Method setter = pd.getWriteMethod();
        System.out.println("    setter: " + ((setter == null) ? "" : setter.getName()));
    }
    

    得到输出

    property name: bar
        getter: getBar
        setter: setBar
    property name: baz
        getter: isBaz
        setter: setBaz
    property name: class
        getter: getClass
        setter: 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 2015-07-16
      • 2013-03-21
      • 1970-01-01
      相关资源
      最近更新 更多