Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum's values() method access level

JLS 8 states that each enum class has implicitly declared method:

public static E[] values();

So, it is public by specification.

At the same time Class.getEnumConstantsShared() method forcibly makes it accessible:

            final Method values = getMethod("values");
            java.security.AccessController.doPrivileged(
                new java.security.PrivilegedAction<Void>() {
                    public Void run() {
                            values.setAccessible(true);
                            return null;
                        }
                    });
            @SuppressWarnings("unchecked")
            T[] temporaryConstants = (T[])values.invoke(null);

I'm wondering: what's the sense?

like image 595
Andremoniy Avatar asked Jan 27 '17 13:01

Andremoniy


1 Answers

Short answer: otherwise it would not work with anything but public Enums

To access the method MyEnum.values(), the method needs to be public (it always is) and MyEnum needs to be public (or it must be in the same package).

The method is accessed from the Class::getEnumConstantsShared() in the package java.lang. So as long as the none public Enum is not in java.lang getEnumConstantsShared() will not have access to it. Access is determined by the direct caller not by somebody higher up the call stack. The direct caller of values.invoke(null) is the code in java.lang.Class so the accessibility rules apply to exactly that context

That can be easily verified (following code will not work) if you create a static method in some package a

public class ValueGetter {
    public static Object[] getValues(Class<? extends Enum> enu) throws Exception {
        Method method = enu.getMethod("values");
        return (Object[]) method.invoke(null);
    }
}

And try to access it like this snippet in a different package b

public class EnumTest {
    enum MyEnum {
        LITERAL;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(Arrays.toString(ValueGetter.getValues(MyEnum.class)));
    }
}
like image 102
k5_ Avatar answered Sep 17 '22 20:09

k5_