Прославленные классы на языке Java

96

Некоторые классы в стандартном API Java обрабатываются несколько иначе, чем другие классы. Я говорю о тех классах, которые невозможно реализовать без специальной поддержки со стороны компилятора и / или JVM.

Вот что я сразу придумываю:

  • Object (очевидно) у него, между прочим, нет суперкласса.
  • String поскольку в языке есть специальная поддержка оператора +.
  • Thread поскольку у него есть этот волшебный метод start (), несмотря на то, что нет инструкции байт-кода, которая «разветвляет» выполнение.

Я полагаю, что все подобные классы так или иначе упомянуты в JLS. Поправьте меня если я ошибаюсь.

Во всяком случае, какие еще существуют такие классы? Есть ли полный список «прославленных классов» в языке Java?

aioobe
источник
2
Дженерики почти подходят, но не совсем. Они реализованы с помощью уловки компилятора, но не изолированы от одного класса.
Bill the Lizard
2
Все они относятся к типам благоговения. ;-)
starblue
1
"Thread.start" волшебный? Неужто для этого был вызван какой-то нативный код?
jcoder
Эта мысль меня тоже поразила. Возможно, одного JNI достаточно для реализации класса Thread. Я полагаю, что если бы я попытался сделать это, я бы использовал некоторый api потока уровня ОС, разветвлял выполнение в реализации метода start (), выполнял метод run () в разветвленном потоке и возвращался. Но тогда мой поток ОС продолжал бы работать. Будет ли это работать гладко вместе с потоками, созданными JVM? а чтить модель памяти JLS и тд?
aioobe
2
Согласно спецификации, единственный способ создать поток - из класса Thread ( java.sun.com/docs/books/jvms/second_edition/html/… ). Конечно, он основан на некотором наивном уровне взаимодействия с JVM, но если вы создали свой собственный JNI, вы могли бы запустить поток, но вы не смогли бы заставить JVM понимать, что вы делаете (блокировки, модель памяти и т. Д.) ). Поток имеет привилегию, поскольку спецификация назначает ему особую привилегию - единственный способ запустить поток.
Ишай

Ответы:

35

Есть много разных ответов, поэтому я подумал, что было бы полезно собрать их все (и добавить несколько):

Классы

  • Классы AutoBoxing - компилятор допускает только определенные классы
  • Класс - имеет свои собственные литералы (например, int.class). Я бы также добавил его общую типизацию без создания новых экземпляров.
  • Строка - с перегруженным + -оператором и поддержкой литералов
  • Enum - единственный класс, который можно использовать в операторе switch (скоро привилегия будет предоставлена ​​и String). Он также выполняет другие задачи (автоматическое создание статических методов, обработка сериализации и т. Д.), Но теоретически это можно сделать с помощью кода - это просто много шаблонов, и некоторые ограничения не могут быть применены в подклассах (например, специальные правила создания подклассов), но то, что вы никогда бы не смогли сделать без привилегированного статуса перечисления, - это включить его в оператор switch.
  • Object - корень всех объектов (и я бы добавил, что методы clone и finalize - это не то, что вы могли бы реализовать)
  • Ссылки : WeakReference, SoftReference, PhantomReference
  • Поток - язык не дает вам конкретной инструкции для запуска потока, скорее он волшебным образом применяет ее к методу start ().
  • Throwable - корень всех классов, которые могут работать с throw, throws и catch, а также понимание компилятором Exception vs. RuntimeException и Error.
  • NullPointerException и другие исключения, такие как ArrayIndexOutOfBounds, которые могут быть выброшены другими инструкциями байт-кода, кроме athrow.

Интерфейсы

  • Iterable - единственный интерфейс, который можно использовать в расширенном цикле for

Почетные упоминания относятся к:

  • java.lang.reflect. Массив - создание нового массива, определенного объектом Class, было бы невозможно.
  • Аннотации Это особая языковая функция, которая во время выполнения ведет себя как интерфейс. Вы, конечно, не можете определить другой интерфейс аннотации, так же как вы не можете определить замену для Object. Однако вы могли бы реализовать все их функции и просто иметь другой способ их получения (и целую кучу шаблонов), а не отражение. Фактически, до появления аннотаций существовало множество реализаций на основе XML и тегов javadoc.
  • ClassLoader - он, безусловно, имеет привилегированные отношения с JVM, поскольку нет языкового способа загрузки класса, хотя есть способ байт-кода, поэтому он похож на Array в этом смысле. Он также имеет особую привилегию быть вызванным JVM, хотя это деталь реализации.
  • Сериализуемый - вы можете реализовать эту функциональность через отражение, но у него есть собственное привилегированное ключевое слово, и вы потратите много времени на знакомство с SecurityManager в некоторых сценариях.

Примечание: я исключил из списка то, что предоставляет JNI (например, ввод-вывод), потому что вы всегда можете реализовать свой собственный вызов JNI, если бы вы были так склонны. Однако собственные вызовы, которые взаимодействуют с JVM привилегированными способами, отличаются.

Массивы спорны - они наследуют Object, имеют понятную иерархию (Object [] - это супертип String []), но они являются особенностями языка, а не определенным классом сами по себе.

Ишай
источник
@Donal, очень верно, я думал об аннотациях во время выполнения, но аннотации на уровне исходного кода действительно были сделаны таким образом (xdoclet наиболее примечательно, или даже в ядре java с @deprecated)
Ишай,
Я только что пробился сквозь массу кода, который изначально был написан с использованием обработки xdoclet, а затем преобразован в аннотации. О, как я предпочитаю аннотации этому (хотя, с подходящими заклинаниями maven, чистый эффект тот же).
Donal Fellows,
@ KK_07k11A0585, Коллекции - это стандартный api, который может быть создан кем угодно по-другому (на самом деле есть альтернативные реализации, ориентированные на примитивы, а также очень известный проект Google, который их улучшает). Единственное, что они получают особенного, - это Iterable, о котором упоминается в ответе. Безусловно, они являются основой программирования на Java, но это обычные классы без каких-либо особых привилегий.
Ишай
@Yishai При разработке любого приложения главное, что имеет значение - УПРАВЛЕНИЕ ДАННЫМИ. Все мы можем выполнять задачу разными способами, но оптимизированный способ - это тот, который занимает меньше памяти и меньше использует ненужные ссылки. Используя Коллекции, мы можем сортировать, искать и сравнивать большой объем данных, что обеспечивает предопределенные алгоритмы, такие как двоичный поиск, сортировка слиянием и т. Д. Он также предоставляет нам компаратор и сопоставимые интерфейсы для настройки наших методов. Класс коллекций может быть не лучшим классом в java, но это, несомненно, класс прославленных качеств.
KK_07k11A0585
1
О чем SecurityManager? Или что-нибудь связанное с отражением или сериализацией?
Antimony
19

Class, конечно. Он имеет свои собственные литералы ( Stringкстати, разделяет его различие ) и является отправной точкой всей этой магии отражения.

Майкл Боргвардт
источник
Ах, хорошее замечание. Итак, каков пример литерала класса? Вы имеете в виду MyClass.class?
aioobe
4
@aioobe: точно. Обратите внимание, что у вас также есть int.class, char.class и т. Д.
Майкл Боргвардт,
12
  1. Enum. Вам не разрешено создавать подклассы, но компилятор может.
  2. Многие вещи в java.util.concurrent можно реализовать без поддержки JVM, но они будут намного менее эффективны.
Даррон
источник
1
Вы можете анонимно создавать подклассы перечислений (которые являются основой шаблона посетителя для значений перечислений). Но да, вы не можете полностью создать подкласс enum ;-)
Тьерри
11

Во всех классах Number есть немного волшебства в виде Autoboxing .

Билл Ящерица
источник
Вы имеете в виду классы, которые обертывают примитивы, включая Boolean и Character; но исключает BigInteger.
Эмори
1
@emory: Верно, только примитивные классы-оболочки. К сожалению, это исключает BigInteger.
Bill the Lizard
10

Поскольку были упомянуты важные классы , я упомяну некоторые интерфейсы:

IterableИнтерфейс (с 1,5) - это позволяет объекту участвовать в цикле Еогеасп:

Iterable<Foo> iterable = ...;
for (Foo foo : iterable) {

}

SerializableИнтерфейс имеет особое значение, отличное от стандартного интерфейса. Вы можете определить методы, которые будут учитываться, даже если они не определены в интерфейсе (например, readResolve()). transientКлючевое слово языка элемент , который влияет на поведение Serializableреализаторов.

Божо
источник
Правда, это интерфейсы, поэтому они не требуют «специальной» реализации для каждого просмотра. (Подобно Throwable.)
aioobe
Сериализуемый действительно требует специальной реализации. Это интерфейс, который, как ожидается, будет иметь два метода (я забыл имена ... Я мог бы погуглить ...), но они не требуются и не определены в стандартной схеме интерфейса.
corsiKa
@glowcoder: однако однажды можно было бы возразить, что вся особенность Serializable не имеет отношения к языку Java, только к реализации ObjectOutputStream и ObjectInputStream.
Майкл Боргвардт,
5
@Michael Borgwardt - transientключевое слово
Божо
1
Не думаю - Comparableни в чем внутреннем не участвует. Вы могли бы легко написать NewComparableи новое NewArrays.sort(..)с той же функциональностью
Божо
6
  1. Throwable , RuntimeException, Error AssertionError
  2. Ссылки WeakReference, SoftReference, PhantomReference
  3. Enum
  4. Аннотации
Эмори
источник
Хороший список. +1, аннотация - это интерфейс, и он не имеет реализации.
aioobe
1
Аннотации обрабатываются компилятором иначе, чем обычные интерфейсы. Как и enum, все они расширяют аннотацию, и компилятор делает это автоматически. Из JavaDoc of Annotation: Общий интерфейс, расширенный для всех типов аннотаций. Обратите внимание, что интерфейс, расширяющий его вручную, не определяет тип аннотации. Также обратите внимание, что этот интерфейс сам по себе не определяет тип аннотации. Таким образом, вы не можете создавать аннотации, используя обычный синтаксис, им нужно было изменить компилятор, чтобы добавить их.
Андрей Фирбинтяну
6

Массив Java, как в int[].class

Александр Погребняк
источник
Ах, молодец! the [Iclass;) это не класс API.
aioobe
2

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

демотика2002
источник
Вы правы, они не могут быть реализованы на чистой Java. Их необходимо реализовать через JNI (как и любой другой класс, которому нужны системные вызовы). Однако, кроме этого, они не нуждаются в специальной поддержке со стороны компилятора или jvm.
aioobe
2

В Systemклассе есть магия .

System.arraycopy это зацепка в машинном коде

public static native void arraycopy(Object array1, int start1, 
  Object array2, int start2, int length);

но...

/**
 * Private version of the arraycopy method used by the jit
 * for reference arraycopies
 */
private static void arraycopy(Object[] A1, int offset1,
  Object[] A2, int offset2, int length) {
   ...
}
Эльдженсо
источник
1
Эй, что ты имеешь в виду под второй частью ответа?
Pacerier
1

Ну, поскольку была упомянута особая обработка assert. Вот еще несколько типов исключений, которые специально обрабатываются jvm:

  • Исключение нулевого указателя
  • ArithmeticException.
  • StackOverflowException
  • Все виды OutOfMemoryErrors
  • ...

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

Josefx
источник
0

Большинство этих классов на самом деле не реализовано с помощью «специальной» помощи компилятора или JVM. Объект действительно регистрирует некоторые "аборигены", которые исследуют внутренние структуры JVM, но вы также можете сделать это для своих собственных классов. (Я допускаю, что это зависит от семантики, «вызовы нативного кода, определенного в JVM» можно рассматривать как специальную поддержку JVM.)

Что / является / особенным, так это поведение инструкций new и throw в том, как они инициализируют эти внутренние структуры.

Однако аннотации и цифры в значительной степени причудливы.

миллимеш
источник
4
aioobe относится к классам, которые вы не можете реализовать самостоятельно, так как они имеют специальную встроенную поддержку. Вы не можете создать свой собственный класс Object как корень системы типов без наследования формы java.lang.Object. Object имеет специальную поддержку со стороны компилятора и jvm, чтобы убедиться, что это корневой класс. Нативных звонков недостаточно, чтобы обойти это.
josefx