调用泛型枚举的getter

时间:2016-03-07 13:57:39

标签: java reflection enums invoke

我需要调用字段访问器方法,即泛型枚举的getter,但无法弄清楚如何调用方法,或者更具体地说,如何将泛型枚举作为invoke-method的参数传递。

在此先感谢,感谢任何帮助。

这是我想或多或少做的事。

public void(Class<? extends Enum<?>> enumType) {
    Enum<?>[] enumConstants = enumType.getEnumConstants();
    String[] text = new String[enumConstants.length];
    String[] names =  new String[enumConstants.length];
    for (int i = 0; i < enumConstants.length; i++ ) {
        Method[] methods = enumConstants[i].getClass().getDeclaredMethods();
        for (Method m: enumConstants[i].getClass().getDeclaredMethods()) {
            System.out.println(enumConstants[i].name() + ": " + m.getName() + "()");
            try {
                if (GET_KEY_METHOD_NAME.equalsIgnoreCase(m.getName())) {
                    Object value = m.invoke(I HAVE NO IDEA WHAT TO PUT HERE, "");
                    System.out.println(value.toString());
                }
                if (GET_VALUE_METHOD_NAME.equalsIgnoreCase(m.getName())) {
                    Object value = m.invoke(I HAVE NO IDEA WHAT TO PUT HERE, "");
                    System.out.println(value.toString());
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

        }
    }

}

2 个答案:

答案 0 :(得分:2)

Method.invoke方法的参数始终是调用方法的实例,后跟参数列表。

Object value = m.invoke(enumConstants[i]);

很可能是你需要的。

另外,您应该在方法中添加一个类型参数:

public <T extends Enum<T>> void myMethod(Class<T> enumType) {
    T[] enumConstants = enumType.getEnumConstants();

BTW:您是否考虑过使用包含这些方法的interface?这将允许您访问方法而无需使用反射。

另请参阅getDeclaredMethod方法,并记住枚举常量可以是枚举类的子类的实例,因此您应该使用不包含Declared的方法。还可以找到枚举类的方法,而不是查找较少查找的单个类:

例如,请考虑以下事项:

public enum MyEnum implements M1M2Interface {
    ONE() {

        @Override
        public String m1(String s) {
            return "1";
        }

    }, TWO() {

        @Override
        public int m2(BigInteger i) {
            return 2;
        }

    }
    ;

}

public interface M1M2Interface {
    default String m1(String s) {
        return "2";
    }

    default int m2(BigInteger i) {
        return 1;
    }
}
public static <T extends Enum<T>> void testEnum(Class<T> enumType) throws NoSuchMethodException {
    T[] enumConstants = enumType.getEnumConstants();
    Method m1 = enumType.getMethod("m1", String.class);
    Method m2 = enumType.getMethod("m2", BigInteger.class);

    for (int i = 0; i < enumConstants.length; i++) {
        System.out.println(enumConstants[i].name() + ":");
        try {
            System.out.println("    m1:" + m1.invoke(enumConstants[i], "Hello World"));
            System.out.println("    m2:" + m2.invoke(enumConstants[i], (BigInteger) null));
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            ex.printStackTrace();
        }
    }
}

getDeclaredMethod在这里不起作用,因为这些方法可以通过以下方式声明/实现:

  • 接口(仅在java 8之前声明)
  • 枚举类
  • 枚举常量(如果在“更高级别”没有声明,则无法使用EnumName.CONSTANT_NAME.methodName()访问该方法,因此不太可能完成...)

答案 1 :(得分:1)

反思很少是对任何事情的正确答案。考虑让您的枚举类实现一个通用接口,例如StandardCopyOptionMonth

如果你不能修改枚举类,并且你正在使用Java 8,你可以将getter方法作为参数传递:

public <E extends Enum<E>> E findMatch(Class<E> enumClass,
                                       Function<E, String> nameGetter,
                                       Predicate<String> matcher) {
    for (E value : EnumSet.allOf(enumClass)) {
        String name = nameGetter.apply(value);
        if (matcher.test(name)) {
            return value;
        }
    }

    return null;
}

使用示例:

public static enum Season {
    SPRING("Spr"),
    SUMMER("Sum"),
    FALL("Fal"),
    WINTER("Win");

    private final String abbreviation;

    private Season(String abbrev) {
        this.abbreviation = abbrev;
    }

    public getAbbreviation() {
        return abbreviation;
    }
}

public void doStuff() {
    // ...

    String abbrToFind = "Sum";
    Season match = findMatch(Season.class,
        Season::getAbbreviation,
        Predicate.isEqual(abbrToFind));
}

如果您使用的是早于Java 8的版本,您仍然可以执行相同的操作,但您需要自己定义和实现这些接口:

public interface Function<A, B> {
    B apply(A input);
}

public interface Predicate<T> {
    boolean test(T value);
}

public void doStuff() {
    // ...

    final String abbrToFind = "Sum";
    Season match = findMatch(Season.class,
        new Function<Season, String>() {
            @Override
            public String apply(Season season) {
                return season.getAbbreviation(),
            }
        },
        new Predicate<String>() {
            @Override
            public boolean test(String name) {
                return Objects.equals(name, abbrToFind);
            }
        });
}