JavaRush /Java блог /Random UA /Reflection API. Як працює метод getModifiers() у класі Cl...
Георгий
22 рівень
Санкт-Петербург

Reflection API. Як працює метод getModifiers() у класі Class

Стаття з групи Random UA
Як пов'язані метод public native int getModifiers()із класу Classта деякі константи із класу Modifier. Reflection API.  Як працює метод getModifiers() у класі Class - 1Припустимо, у нас є клас:
public static abstract class NestedClass{
}
Метод getModifiers()повертає результат у вигляді числа, в якому зашифровані модифікатори доступу того класу або методу, у якого він викликаний. Щоб викликати getModifiers()для класу, наприклад NestedClass, для створення об'єкта класу Classдля класу NestedClass. А вже на об'єкті класу Class<NestedClass>викликати getModifiers().
Class<NestedClass> c = NestedClass.class;
int classModifiers = c.getModifiers();
Або в один рядок і виведемо на екран результат та його двійкове уявлення:
int classModifiers = NestedClass.class.getModifiers();
System.out.printf("classModifier = %d%n",classModifiers);
System.out.printf("classModifier в двоичной системе счисления = %s%n",Integer.toBinaryString(classModifiers));
На екрані:

classModifiers = 1033
classModifiers в двоичной системе счисления = 10000001001
Добре, але чому саме це число? Давайте розбиратися на прикладі класу NestedClass. Допустимо, у нас є метод:
public static boolean isModifierSet(int allModifiers, int specificModifier) {
}
У його параметри надходитимуть: int allModifiers = NestedClass.class.getModifiers(), як із прикладу вище. А int specificModifierдорівнюватиме якийсь із констант класу Modifier: Modifier.PUBLIC, Modifier.STATICі т.п. (Інші константи розглянемо нижче). І метод буде повертати нам trueякщо клас містить модифікатор доступу, переданий в specificModifier. Якщо ні – false. Код у тестовому класі виглядатиме так:
boolean isPublic = isModifierSet(classModifiers, Modifier.PUBLIC);
boolean isInterface = isModifierSet(classModifiers, Modifier.INTERFACE);
boolean isAbstract = isModifierSet(classModifiers, Modifier.ABSTRACT);

System.out.printf("\"Is NestedClass public?\" - %b%n", isPublic); //true
System.out.printf("\"Is NestedClass interface?\" - %b%n", isInterface); //false
System.out.printf("\"Is NestedClass abstract?\" - %b%n", isAbstract); //true
Як же реалізувати логіку методу isModifierSet? Представимо у двійковій системі модифікатори в класі Modifier: (наприклад, Modifier.FINAL= 0x00000010, або в 10-й системі - 16. 16 у двійковій = 00010000)
  • Modifier.PUBLIC = 1 = 0000 0001
  • Modifier.PRIVATE= 2 = 0000 0010
  • Modifier.PROTECTED= 4 = 0000 0100
  • Modifier.STATIC= 8 = 0000 1000
  • Modifier.FINAL= 16 = 0001 0000
  • Modifier.SYNCHRONIZED= 32 = 0010 0000
  • Modifier.VOLATILE= 64 = 0100 0000
  • Modifier.TRANSIENT= 128 = 1000 0000
  • Modifier.NATIVE= 256 = 1 0000 0000
  • Modifier.INTERFACE= 512 = 10 0000 0000
  • Modifier.ABSTRACT = 1024 = 100 0000 0000
  • NestedClass.class.getModifiers()= 1033 = 100 0000 1001
І що ми бачимо? Для кожного модифікатора взято таке число в десятій, щоб у другій у них одна рухалася на розряд вліво. А getModifiers()обчислюється в такий спосіб, що й клас містить певний модифікатор доступу, такий самий розряд, як й у модифікаторі доступу, стає рівним 1. У NestedClassтакі модифікатори доступа: public static abstract. В PUBLICодиниці дорівнює 0 розряд (крайній праворуч). В STATIC- 3. В ABSTRACT- 10. І тепер дивимося на наш NestedClass.class.getModifiers(): У 0, 3 та 10 розрядах у нього одиниця! А решта нуль. Далі переходимо до розв'язання задачі. Ми повинні зрозуміти, чи містить наш getModifiers()певний модифікатор. Розглянемо випадок для модифікатора final. Modifier.FINAL= 16 = 0001 0000, отже одиниці дорівнює 4 розряд. За аналогією з прикладом вище, дивимося, чи містить нашNestedClass.class.getModifiers()= 100 0000 1001 Modifier.FINAL. Тут 4 розряд дорівнює 0. Значить не містить, що відповідає дійсності ( NestedClassне final). Але яку логіку писати у методі? Потрібно застосувати логічне AND (&), яке дорівнює 1, якщо обидва біти дорівнюють 1. В інших випадках 0. Наш метод остаточно буде виглядати так:
public static boolean isModifierSet(int allModifiers, int specificModifier) {
        return (allModifiers & specificModifier) > 0;
    }
Переконаємося, що код працює і покажемо, чому він працює. Обчислюємо NestedClass.class.getModifiers() & Modifier.FINAL:
  • 100 0000 1001 -NestedClass.class.getModifiers()
  • 000 0001 0000 - Modifier.FINAL(додали зліва 3 нуля для зручності)
  • 000 0000 0000 - відповідь 0. Ми не маємо жодної одиниці, т.к. тільки 1&1=1. 1&0=0, 0&1=0, 0&0=0;
Значить наш вираз у returnповерне false, т.к. 0> 0 - false. Значить, такого модифікатора доступу немає. Дивимося Modifier.ABSTRACT & NestedClass.class.getModifiers():
  • 100 0000 0000 -Modifier.ABSTRACT
  • 100 0000 1001 -NestedClass.class.getModifiers()
  • 100 0000 0000 - Збіглися крайні одиниці зліва. Перекладаємо в десяту: відповідь 1024.
Значить наш вираз у returnповерне true, т.к. 1024 > 0 - true. Значить, такий модифікатор доступу є. Reflection API.  Як працює метод getModifiers() у класі Class - 2Так само цей метод можна застосовувати і до методів класу, і до полів класу. Код для поля виглядатиме так:
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class A {
    private static transient volatile String name = "Bob";

    public static void main(String[] args) throws NoSuchFieldException {

        Field field = A.class.getDeclaredField("name");
        int fieldModifiers = field.getModifiers();

        boolean isPublic = isModifierSet(fieldModifiers, Modifier.PUBLIC);
        boolean isFinal = isModifierSet(fieldModifiers, Modifier.FINAL);
        boolean isVolatile = isModifierSet(fieldModifiers, Modifier.VOLATILE);

        System.out.printf("\"Is A.name public?\" - %b%n", isPublic); //false
        System.out.printf("\"Is A.name final?\" - %b%n", isFinal); //false
        System.out.printf("\"Is A.name volatile?\" - %b%n", isVolatile); //true
    }
    public static boolean isModifierSet(int allModifiers, int specificModifier) {
        return (allModifiers & specificModifier) > 0;
    }
}
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ