JavaRush /Блог /Random /Reflection API. Как работает метод getModifiers() в класс...
Георгий
22 уровень
Санкт-Петербург

Reflection API. Как работает метод getModifiers() в классе Class

Статья из группы Random
Как связаны метод 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
И что мы видим? Для каждого модификатора взято такое число в 10-ной, чтобы в 2-ной у них 1 двигалась на разряд влево. А 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 - Совпали крайние единицы слева. Переводим в 10-ную: ответ 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;
    }
}
Комментарии (71)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Light_Day :) Уровень 44
14 июля 2024
отличная статья!!!!
Pavel Fetisov Уровень 30
7 июня 2024
Вообще всё понял, спасибо!
Юлия Уровень 33
30 мая 2023
Спасибо большое! Очень хорошо написано 👍
partiec Уровень 33
26 апреля 2023
Видел в интернетах ролик, где люди пса покормили голодающего. Как он радовался! Спасибо и за статью, и за задачу. Чувствую себя как этот пес, которого чморили долго, а потом корочку бросили, чтоб он совсем уж не расстраивался😁.
partiec Уровень 33
25 апреля 2023
Достойная статья.
LE_Anonymous #3029647 Уровень 38
13 января 2023
Спасибо.
MRamazanov Уровень 30
1 января 2023
Спасибо большое автору, чтобы побольше таких статей было.
Николай Уровень 27
29 сентября 2022
Спасибо, очень доходчиво)
Зета Медведя Уровень 45
1 сентября 2022
Я после прочтения и понимания этой статьи:
И. Ж. Уровень 41
6 августа 2022
Шикарно, развернуто, подробно!