Прославлені заняття мовою Java


96

Деякі класи в стандартному Java API обробляються дещо інакше, ніж інші класи. Я говорю про ті класи, які неможливо реалізувати без спеціальної підтримки компілятора та / або JVM.

Ті, які я придумую відразу:

  • Object (очевидно), оскільки воно, крім усього іншого, не має суперкласу.
  • String оскільки мова має спеціальну підтримку для оператора +.
  • Thread оскільки він має цей магічний метод start (), незважаючи на те, що не існує інструкції байт-коду, яка б "розгалужувала" виконання.

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

У будь-якому разі, які ще такі класи існують? Чи існує повний список "прославлених класів" мовою Java?


2
Дженерики майже підходять, але не зовсім. Вони реалізовані з використанням трюку компілятора, але вони не ізольовані до одного класу.
Білл Ящірка

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, що ви робите (замки, модель пам'яті тощо). ). Потік має привілей, оскільки специфікація надає йому особливий привілей - єдиний спосіб запустити потік.
Yishai

Відповіді:


35

Є багато різних відповідей, тому я вважав, що було б корисно зібрати їх усі (і додати деякі):

Заняття

  • Класи AutoBoxing - компілятор дозволяє лише певні класи
  • Клас - має власні літерали (наприклад, int.class). Я також додав би його загальне введення, не створюючи нових екземплярів.
  • Рядок - з його перевантаженим + -оператором та підтримкою літералів
  • Enum - єдиний клас, який можна використовувати в операторі switch (незабаром привілей також буде наданий String). Він робить і інші речі (автоматичне створення статичного методу, обробка серіалізації тощо), але теоретично це можна зробити за допомогою коду - це просто багато зразків, і деякі обмеження не можуть бути застосовані в підкласах (наприклад, спеціальні правила підкласування), але те, чого ви ніколи не змогли б досягти без привілейованого статусу переліку, - це включити його до оператора switch.
  • Об'єкт - корінь усіх об'єктів (і я хотів би додати його клонування та методи завершення - це не те, що ви могли б реалізувати)
  • Список літератури : WeakReference, SoftReference, PhantomReference
  • Потік - мова не дає вам конкретних вказівок для запуску потоку, а чарівніше застосовує його до методу start ().
  • Throwable - корінь усіх класів, які можуть працювати з методами throw, throws і catch, а також розуміння компілятором винятків проти RuntimeException та Error.
  • NullPointerException та інші винятки, такі як ArrayIndexOutOfBounds, які можуть бути викинуті іншими інструкціями байтового коду, ніж athrow.

Інтерфейси

  • Iterable - єдиний інтерфейс, який можна використовувати в розширеному циклі for

Почесні згадки дістаються:

  • java.lang.reflect. Масив - створення нового масиву, визначеного об’єктом Класу, було б неможливим.
  • Анотації Вони є особливою мовною функцією, яка поводиться як інтерфейс під час виконання. Ви, звичайно, не змогли визначити інший інтерфейс анотації, як і ви не можете визначити заміну для об’єкта. Однак ви можете реалізувати всю їх функціональність і просто мати інший спосіб отримати їх (і цілу купу зразкових даних), а не відображення. Насправді, до впровадження анотацій було багато реалізацій на основі XML та тегів Java.
  • ClassLoader - він, безумовно, має привілейовані відносини з JVM, оскільки не існує жодного мовного способу завантаження класу, хоча існує спосіб байт-коду, тому він таким чином схожий на Array. Він також має особливий привілей передзвонити JVM, хоча це є деталлю реалізації.
  • Серіалізується - ви можете реалізувати функціонал за допомогою роздумів, але у нього є власне привілейоване ключове слово, і ви витрачаєте багато часу на знайомство з SecurityManager в деяких сценаріях.

Примітка: Я залишив поза списком речі, які надають JNI (наприклад, IO), тому що ви завжди можете реалізувати власний виклик JNI, якщо ви були настільки схильні. Однак власні дзвінки, які взаємодіють із JVM привілейованими способами, різні.

Масиви дискусійні - вони успадковують Object, мають зрозумілу ієрархію (Object [] є надтипом String []), але вони є мовною ознакою, а не визначеним класом самі по собі.


@Donal, дуже правда, я думав про анотацію виконання, але анотації рівня джерела справді були зроблені саме таким чином (xdoclet найпомітніше, або навіть в ядрі Java з @deprecated)
Yishai

Я щойно пробивався через хащу коду, який спочатку був написаний з обробкою xdoclet, а потім перетворений на анотації. О, як я віддаю перевагу анотаціям перед цим (хоча, з відповідними заклинаннями Maven, чистий ефект однаковий).
Donal Fellows

@ KK_07k11A0585, Колекції - це стандартний API, який кожен може створити по-різному (насправді існують альтернативні реалізації, орієнтовані на примітиви, а також дуже відомий проект Google, який їх покращує). Єдине, що вони отримують, що є особливим, це Iterable, про що йдеться у відповіді. Звичайно, це хліб і масло Java-програмування, але це просто звичайні заняття, без особливих привілеїв.
Yishai,

@Yishai Під час розробки будь-якого додатка головне, що набуває важливого значення, - це УПРАВЛІННЯ ДАНИМИ. Ми всі можемо виконувати завдання різною кількістю способів, але оптимізованим способом є той, який займає менше пам'яті і в якому менше використовується непотрібних посилань. Використовуючи колекції, ми можемо сортувати, шукати та порівнювати велику кількість даних, що забезпечує заздалегідь визначені алгоритми, такі як двійковий пошук, злиття та ін. Сортування тощо. Також ми пропонуємо порівняльний та порівняльний інтерфейси для налаштування наших методів. Клас колекцій може бути не найкращим класом у Java, але це, безсумнівно, клас прославлених якостей.
KK_07k11A0585

1
Що про SecurityManager? Або що-небудь пов’язане з роздумами чи серіалізацією?
Сурма

19

Class, звичайно. Він має свої власні літерали (відмінність, якими він поділяється String, BTW) і є відправною точкою всієї цієї магії відображення.


Ах, гарна думка. Отже, який приклад літерального класу? Ви маєте на увазі MyClass.class?
aioobe

4
@aioobe: точно. Зверніть увагу, що у вас також є int.class, char.class тощо
Michael Borgwardt


12
  1. Перелік. Вам не дозволено підкласувати його, але компілятор може.
  2. Багато речей у java.util.concurrent можна реалізувати без підтримки JVM, але вони були б набагато менш ефективними.

1
Ви можете анонімно підкласувати перелічення (що є основою шаблону відвідувача, включеного для значень переліків). Але так, ви не можете повністю підкласувати перерахування ;-)
Тьєррі,

11

Всі класи Number мають трохи магії у вигляді автобоксу .


Ви маєте на увазі класи, які обертають примітиви - до яких також входять логічні значення та символ; але виключає BigInteger.
emory

1
@emory: Правильно, просто примітивні класи обгортки. На жаль, це виключає BigInteger.
Білл Ящірка

10

Оскільки були згадані важливі класи , я згадаю деякі інтерфейси:

IterableІнтерфейс (з 1,5) - це дозволяє об'єкту брати участь в циклі Еогеасп:

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

}

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


Правда, вони все-таки є інтерфейсами, тому вони не потребують "спеціального" впровадження на перегляд. (Подібно до Throwable.)
aioobe

Серіалізація насправді вимагає спеціального впровадження. Це інтерфейс, який, як очікується, матиме два методи (я забуваю імена ... я міг би погуглити ...), але вони не є обов’язковими або визначеними у стандартній схемі інтерфейсу.
corsiKa

@glowcoder: однак, колись міг стверджувати, що вся особливість Serializable не стосується мови Java, а лише реалізації ObjectOutputStream та ObjectInputStream.
Michael Borgwardt

5
@Michael Borgwardt має - transientключове слово
Божо

1
Я не думаю - Comparableне бере участі ні в чому внутрішньому. Ви можете легко писати NewComparableта писати новинки NewArrays.sort(..)з однаковою функціональністю
Божо

6
  1. Throwable , RuntimeException, Error AssertionError
  2. Посилання WeakReference, SoftReference, PhantomReference
  3. Енум
  4. Анотація

Хороший список. +1, Анотація є інтерфейсом і не має реалізації.
aioobe

1
Анотації обробляються компілятором інакше, ніж звичайні інтерфейси. Подібно до enum, всі вони розширюють Annotation, і компілятор робить це автоматично. З JavaDoc Annotation: Спільний інтерфейс, розширений усіма типами анотацій. Зауважте, що інтерфейс, який розширює цей вміст вручну, не визначає тип анотації. Також зауважте, що сам цей інтерфейс не визначає тип анотації. Тому ви не можете створити анотацію, використовуючи звичайний синтаксис, їм потрібно було змінити компілятор, щоб додати їх.
Андрій Фієрбінтяну,



2

Не впевнений у цьому. Але я не можу придумати спосіб ручної реалізації об'єктів вводу-виводу.


Ви маєте рацію, їх не можна реалізувати на чистій 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

Ну, оскільки згадувалося про спеціальне поводження з твердженням. Ось ще декілька типів винятків, які мають особливе ставлення до jvm:

  • NullPointerException
  • ArithmeticException.
  • StackOverflowException
  • Всі види OutOfMemoryErrors
  • ...

Винятки не є особливими, але jvm використовує їх у особливих випадках, тому ви не можете реалізувати їх самостійно, не написавши власний jvm. Я впевнений, що навколо є більше особливих винятків.


0

Більшість із цих класів насправді не реалізовані за допомогою "спеціальної" допомоги компілятора або JVM. Об’єкт справді реєструє деяких тубільців, які тикаються навколо внутрішніх структур JVM, але ви можете зробити це і для власних класів. (Я визнаю, що це підпорядковується семантиці, "дзвінки носія, визначені в JVM", можуть розглядатися як спеціальна підтримка JVM.)

Що / є / особливим є поведінка "нових" та "кидок" інструкцій у тому, як вони ініціалізують ці внутрішні структури.

Анотації та цифри, втім, дуже дивні.


4
aioobe відноситься до класів, які ви не можете реалізувати самостійно, оскільки вони мають спеціальну підтримку. Ви не можете створити власний клас Object як кореневу систему типу, не успадкувавши форму java.lang.Object. Об'єкт має спеціальну підтримку як компілятора, так і jvm, щоб переконатися, що це кореневий клас. Рідних дзвінків недостатньо, щоб обійти це.
josefx
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.