Как связаны метод
public native int getModifiers()
из класса Class
и некоторые константы из класса Modifier
.
Допустим, у нас имеется класс:
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 0001Modifier.PRIVATE
= 2 = 0000 0010Modifier.PROTECTED
= 4 = 0000 0100Modifier.STATIC
= 8 = 0000 1000Modifier.FINAL
= 16 = 0001 0000Modifier.SYNCHRONIZED
= 32 = 0010 0000Modifier.VOLATILE
= 64 = 0100 0000Modifier.TRANSIENT
= 128 = 1000 0000Modifier.NATIVE
= 256 = 1 0000 0000Modifier.INTERFACE
= 512 = 10 0000 0000Modifier.ABSTRACT
= 1024 = 100 0000 0000NestedClass.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 - Совпали крайние единицы слева. Переводим в 10-ную: ответ 1024.
return
вернёт true
, т.к. 1024 > 0 - true
. Значит такой модификатор доступа есть.
Таким же образом этот метод можно применять и к методам класса, и к полям класса. Код для поля будет выглядеть следующим образом:
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;
}
}
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ