Подтвердить что ты не робот

Почему модификаторы примитивов Java являются "public", "abstract" и "final"?

В процессе некоторого размышления о типах Java я сталкивался с странностью, которую я не понимаю.

Проверка int для его модификаторов возвращает public, abstract и final. Я понимаю public и final, но наличие abstract для примитивного типа для меня неочевидно. Почему это так?

Изменить: я не задумываюсь о Integer, а о int:

import java.lang.reflect.Modifier;

public class IntegerReflection {
    public static void main(final String[] args) {
        System.out.println(String.format("int.class == Integer.class -> %b", int.class == Integer.class));
        System.out.println(String.format("int.class modifiers: %s", Modifier.toString(int.class.getModifiers())));
        System.out.println(String.format("Integer.class modifiers: %s", Modifier.toString(Integer.class.getModifiers())));
    }
}

Выход при запуске:

int.class == Integer.class -> false
int.class modifiers: public abstract final
Integer.class modifiers: public final
4b9b3361

Ответ 1

Если вы запустите

System.out.println(Modifier.toString(int.class.getModifiers()));

вы получаете

public abstract final

возможно потому, что вы не можете подклассифицировать его - то есть final, и вы не можете его создать, т.е. абстрактно.

Из Oracle Абстрактные методы и классы

Абстрактные классы не могут быть созданы, но они могут быть подклассами.

Дело в том, что он также окончательный означает, что он не может быть подклассами.

Ответ 2

В соответствии с JLS 8.1.1.1 - Абстрактные классы:

Абстрактный класс является неполным или считается неполным.

По определению не может быть экземпляров int.class. Вы не можете скомпилировать этот код:

int a = new int();

Нет конструкторов для int. Созданных объектов нет. int.class даже не расширяется Object. Если вы запустите следующую строку кода, вы получите null в качестве результата.

System.out.println(int.class.getSuperclass());

Итак, поскольку у вас никогда не может быть истинного экземпляра int.class, он по определению abstract. Кроме того, в соответствии с Integer API поле Integer.TYPE (которое содержит int.class) является классом, который представляет только примитивный тип.

Это подтверждается следующим кодом:

int a = 4;
System.out.println(int.class.isInstance(a));

Это возвращает false.

Таким образом, int.class скорее всего используется в системе для целей представления, как сказано в API Integer. Тот факт, что существует также тип void.class, но не тип null.class, заставляет меня думать, что это используется в основном с Reflection. Это всего лишь гипотеза.


Если кому-то интересно, int.class по существу не содержит ничего, что пакет отражения распознает и, скорее всего, просто фиктивный класс. Если вы запустите следующий код, вы увидите, что у него нет конструкторов, полей и методов.

Method[] intMethods = int.class.getMethods();

if(intMethods.length == 0) {
    System.out.println("No methods.");
}
else {
    for(Method method : intMethods) {
        System.out.println(method.getName());
    }
}

Constructor[] intConstructors = int.class.getConstructors();

if(intConstructors.length == 0) {
    System.out.println("No constructors.");
}
else {
    for(Constructor constructor: intConstructors) {
        System.out.println(constructor.getName());
    }
}

Field[] intFields = int.class.getFields();

if(intFields.length == 0) {
    System.out.println("No fields.");
}
else {
    for(Field field: intFields) {
        System.out.println(field.getName());
    }
}

Ответ 3

Из спецификации JVM:

Абстрактный класс - неполный неполный класс или считается неполным. Только абстрактные классы могут иметь абстрактные методы, т.е. которые объявлены, но еще не реализованы.

Класс может быть объявлен окончательным, если его определение завершено и никаких подклассов не требуется или требуется. Потому что у последнего класса никогда не было любые подклассы, методы последнего класса не могут быть переопределены в подкласс. Класс не может быть как окончательным, так и абстрактным, поскольку реализация такого класса никогда не может быть завершена.

В соответствии с спецификациями класс не может быть как абстрактным, так и финальным. Но, однако, похоже, что JVM не рассматривает примитивные типы как классы, что является технически корректным, поскольку примитивные типы являются не классами и предоставляются JVM языковой среде (с использованием Class getPrimitiveClass(const char *name)).

So int, и любой другой примитивный тип,

> a. Should be accessible from within the language: Make it `public` 
> b. Should not be extensible                     : Make it `final` 
> c. Should not be instantiated with `new`        : Make it `abstract`.

Моя теория из спецификации JVM объясняет, почему примитивные типы abstract - это потому, что они считаются неполными.

Ответ 4

int.class также доступен как Integer.TYPE и является экземпляром класса, представляющим примитивный тип int.

Учитывая, что вы не можете создать экземпляр объекта этого класса (поскольку ints не являются экземплярами, они являются примитивными типами), я считаю, что имеет смысл иметь тип, помеченный abstract.

На данный момент я не могу найти ссылку на ссылку JLS, хотя.

Ответ 5

Может быть, это просто особый знак для primitive class отличный от normal class.

Реализация кода JVM:

mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class,
                                                     Primitive::Type type) {

  Handle<mirror::Class> h_class(hs.NewHandle(primitive_class));
  // public final static
  h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
  h_class->SetPrimitiveType(type);
  h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());

  // ...
  return h_class.Get();
}

Ответ 6

если вы отразились на класс, унаследованный от абстрактного класса, а затем попытались выкопать в базовый класс для этого экземпляра, свойство, определенное как абстрактное в абстрактном классе, не имеет значения, но оно является частью класса определение.

Вот пример:

public class absBase{

    private string name;
    private int ID;

    public abstract int GetID();
}

public class concreteClass:absBase{
    @Override
    public int GetID(){
        return ID + 1;
    }
}

поэтому, если вы отражали absBase и смотрели на GetID, он должен был быть абстрактным по определению, если бы вы посмотрели на specificClass.GetID(), но он был бы общедоступным. надеюсь, что это поможет.