Classes glorifiées dans le langage Java


96

Certaines classes de l'API Java standard sont traitées légèrement différemment des autres classes. Je parle de ces classes qui ne pourraient pas être implémentées sans un support spécial du compilateur et / ou de la JVM.

Ceux que je propose tout de suite sont:

  • Object (évidemment) car il, entre autres choses, n'a pas de super classe.
  • String car la langue a un support spécial pour l'opérateur +.
  • Thread car il a cette méthode magique start () malgré le fait qu'il n'y a pas d'instruction bytecode qui "fourche" l'exécution.

Je suppose que toutes les classes comme celles-ci sont d'une manière ou d'une autre mentionnées dans le JLS. Corrige moi si je me trompe.

Quoi qu'il en soit, quelles autres classes existent? Existe-t-il une liste complète des «classes glorifiées» dans le langage Java?


2
Les génériques conviennent presque, mais pas tout à fait. Ils sont implémentés à l'aide d'une astuce de compilateur, mais ils ne sont pas isolés à une classe.
Bill the Lizard

2
Ce sont tous des types de révérence. ;-)
starblue

1
"Thread.start" est-il magique? C'est sûrement juste un code natif appelé pour faire cela?
jcoder

Cette pensée m'a également frappé. Peut-être que le JNI seul est suffisant pour implémenter la classe Thread. Je suppose que si j'essayais de faire cela, j'utiliserais une API de thread au niveau du système d'exploitation, je bifurquerais l'exécution dans l'implémentation de la méthode start (), exécuterais la méthode run () dans le thread fourchu et retournerais. Mais alors mon thread OS continuerait à fonctionner. Cela fonctionnerait-il sans problème avec les threads créés par la JVM? et honorer le modèle de mémoire JLS et ainsi de suite?
aioobe

2
Selon la spécification, la seule façon de créer un thread est à partir de la classe Thread ( java.sun.com/docs/books/jvms/second_edition/html/… ). Bien sûr, cela repose sur une communication de niveau naitive avec la JVM, mais si vous avez créé votre propre JNI, vous pouvez démarrer un thread, mais vous ne pourrez pas faire comprendre à la JVM ce que vous faites (verrous, modèle de mémoire, etc. ). Thread est privilégié en ce que la spécification lui attribue un privilège spécial - la seule façon de démarrer un thread.
Yishai

Réponses:


35

Il y a beaucoup de réponses différentes, j'ai donc pensé qu'il serait utile de toutes les rassembler (et d'en ajouter):

Des classes

  • Classes AutoBoxing - le compilateur n'autorise que des classes spécifiques
  • Classe - a ses propres littéraux (int.class par exemple). J'ajouterais également son typage générique sans créer de nouvelles instances.
  • String - avec son opérateur + surchargé et le support des littéraux
  • Enum - la seule classe qui peut être utilisée dans une instruction switch (bientôt un privilège à donner également à String). Il fait également d'autres choses (création automatique de méthodes statiques, gestion de la sérialisation, etc.), mais celles-ci pourraient théoriquement être accomplies avec du code - c'est juste beaucoup de passe-partout, et certaines des contraintes ne pourraient pas être appliquées dans les sous-classes (par exemple, le règles spéciales de sous-classification) mais ce que vous ne pourriez jamais accomplir sans le statut privilégié d'une énumération est de l'inclure dans une instruction switch.
  • Object - la racine de tous les objets (et j'ajouterais ses méthodes de clonage et de finalisation ne sont pas quelque chose que vous pourriez implémenter)
  • Références : WeakReference, SoftReference, PhantomReference
  • Thread - le langage ne vous donne pas d'instructions spécifiques pour démarrer un thread, il l'applique plutôt comme par magie à la méthode start ().
  • Throwable - la racine de toutes les classes qui peuvent fonctionner avec throw, throws et catch, ainsi que la compréhension du compilateur d'Exception par rapport à RuntimeException et Error.
  • NullPointerException et d'autres exceptions telles que ArrayIndexOutOfBounds qui peuvent être levées par d'autres instructions de bytecode que athrow.

Interfaces

  • Iterable - la seule interface qui peut être utilisée dans une boucle for améliorée

Les mentions honorables vont à:

  • java.lang.reflect. Array - la création d'un nouveau tableau tel que défini par un objet Class ne serait pas possible.
  • Annotations Il s'agit d'une fonctionnalité de langage spéciale qui se comporte comme une interface au moment de l'exécution. Vous ne pouvez certainement pas définir une autre interface d'annotation, tout comme vous ne pouvez pas définir un remplacement pour Object. Cependant, vous pouvez implémenter toutes leurs fonctionnalités et avoir juste un autre moyen de les récupérer (et tout un tas de passe-partout) plutôt que de réfléchir. En fait, il y avait de nombreuses implémentations basées sur XML et basées sur des balises javadoc avant l'introduction des annotations.
  • ClassLoader - il a certainement une relation privilégiée avec la JVM car il n'y a pas de langage pour charger une classe, bien qu'il y ait un moyen de bytecode, donc c'est comme Array de cette façon. Il a également le privilège spécial d'être rappelé par la JVM, bien que ce soit un détail d'implémentation.
  • Sérialisable - vous pouvez implémenter la fonctionnalité via la réflexion, mais elle a son propre mot-clé privilégié et vous passeriez beaucoup de temps à vous familiariser avec SecurityManager dans certains scénarios.

Remarque: j'ai omis de la liste les éléments qui fournissent JNI (comme IO) car vous pouvez toujours implémenter votre propre appel JNI si vous le souhaitez. Cependant, les appels natifs qui interagissent avec la JVM de manière privilégiée sont différents.

Les tableaux sont discutables - ils héritent d'Object, ont une hiérarchie comprise (Object [] est un supertype de String []), mais ils sont une fonctionnalité de langage, pas une classe définie en soi.


@Donal, très vrai, je pensais à l'annotation d'exécution, mais les annotations au niveau de la source ont en effet été faites de cette façon (xdoclet surtout, ou même dans le noyau Java avec @deprecated)
Yishai

Je viens de me frayer un chemin à travers un fourré de code qui a été initialement écrit avec le traitement xdoclet, puis converti en annotations. Oh, comme je préfère les annotations à cela (même si, avec des incantations maven appropriées, l'effet net est le même).
Donal Fellows

@ KK_07k11A0585, Les collections sont une API standard qui pourrait être construite par n'importe qui d'une manière différente (en fait, il existe des implémentations alternatives qui sont axées sur les primitives, ainsi qu'un projet Google très célèbre qui les améliore). La seule chose qu'ils obtiennent qui est spéciale est Iterable, qui est mentionnée dans la réponse. Ils sont le pain et le beurre de la programmation Java, bien sûr, mais ce ne sont que des cours réguliers, sans privilèges spéciaux.
Yishai

@Yishai Lors du développement d'une application, la principale chose qui prend de l'importance est la GESTION DES DONNÉES. Nous pouvons tous faire une tâche de différentes manières, mais la manière optimisée est celle qui occupe moins de mémoire et qui utilise moins de références inutiles. En utilisant des collections, nous pouvons trier, rechercher et comparer une grande quantité de données, ce qui fournit des algorithmes prédéfinis comme la recherche binaire, le tri par fusion, etc. Il nous fournit également des comparateurs et des interfaces comparables pour personnaliser nos techniques. La classe Collections n'est peut-être pas la meilleure classe en Java, mais c'est sans aucun doute une classe de qualités glorifiées.
KK_07k11A0585

1
Et quoi SecurityManager? Ou quoi que ce soit lié à la réflexion ou à la sérialisation?
Antimoine

19

Class, bien sûr. Il a ses propres littéraux (une distinction avec laquelle il partage String, BTW) et est le point de départ de toute cette magie de réflexion.


Ah, bon point. Alors, quel est un exemple de littéral de classe? Faites-vous référence à MyClass.class?
aioobe

4
@aioobe: exactement. Notez que vous avez également int.class, char.class, etc.
Michael Borgwardt


12
  1. Enum. Vous n'êtes pas autorisé à le sous-classer, mais le compilateur le peut.
  2. Beaucoup de choses sous java.util.concurrent peuvent être implémentées sans le support JVM, mais elles seraient beaucoup moins efficaces.

1
Vous pouvez sous-classer de manière anonyme les énumérations (qui est la base de l'implication du modèle de visiteur pour les valeurs d'énumérations). Mais oui, vous ne pouvez pas sous-classer complètement une énumération ;-)
Thierry

11

Toutes les classes Number ont un peu de magie sous la forme d' Autoboxing .


Vous voulez dire les classes qui encapsulent les primitives - qui incluent également Boolean et Character; mais exclut BigInteger.
emory

1
@emory: Oui, juste les classes primitives de wrapper. Malheureusement, cela exclut BigInteger.
Bill the Lizard

10

Puisque les classes importantes ont été mentionnées, je mentionnerai quelques interfaces:

L' Iterableinterface (depuis 1.5) - elle permet à un objet de participer à une boucle foreach:

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

}

L' Serializableinterface a une signification très particulière, différente d'une interface standard. Vous pouvez définir des méthodes qui seront prises en compte même si elles ne sont pas définies dans l'interface (like readResolve()). Le transientmot-clé est l'élément de langage qui affecte le comportement des Serializableimplémenteurs.


Certes, ce sont des interfaces, donc elles ne nécessitent aucune implémentation «spéciale» à la vue. (Similaire à Throwable.)
aioobe

Serializable nécessite en fait une implémentation spéciale. C'est une interface que vous attendez d'avoir deux méthodes (j'oublie les noms ... je pourrais google ...) mais elles ne sont pas requises ou définies dans le schéma d'interface standard.
corsiKa

@glowcoder: cependant, une fois pourrait soutenir que toute la particularité de Serializable n'est pas pertinente pour le langage Java, seulement pour l'implémentation d'ObjectOutputStream et d'ObjectInputStream.
Michael Borgwardt

5
@Michael Borgwardt il a - le transientmot
Bozho

1
Je ne pense pas - Comparablene participe à rien d’intérieur. Vous pouvez facilement écrire NewComparableet nouveau NewArrays.sort(..)avec la même fonctionnalité
Bozho

6
  1. Throwable , RuntimeException, Erreur AssertionError
  2. Références WeakReference, SoftReference, PhantomReference
  3. Enum
  4. Annotation

Belle liste. +1, Annotation est cependant une interface et n'a pas d'implémentation.
aioobe

1
Les annotations sont traitées différemment par le compilateur que les interfaces normales. Semblables à enum, ils étendent tous Annotation, et le compilateur le fait automatiquement. Depuis le JavaDoc of Annotation: L'interface commune étendue par tous les types d'annotations. Notez qu'une interface qui étend manuellement celle-ci ne définit pas de type d'annotation. Notez également que cette interface ne définit pas elle-même un type d'annotation. Donc, vous ne pouvez pas créer une annotation en utilisant la syntaxe normale, ils devaient changer le compilateur pour les ajouter.
Andrei Fierbinteanu



2

Pas sûr à ce sujet. Mais je ne peux pas penser à un moyen d'implémenter manuellement des objets IO.


Vous avez raison, ils ne peuvent pas être implémentés en Java pur. Ils doivent être implémentés via JNI (comme toute autre classe devant faire des appels système). En dehors de cela cependant, ils n'ont pas besoin de support spécial du compilateur ou de jvm.
aioobe

2

Il y a de la magie dans la Systemclasse.

System.arraycopy est un crochet dans le code natif

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

mais...

/**
 * 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
Heys, que voulez-vous dire par votre deuxième partie de la réponse?
Pacerier

1

Eh bien, depuis le traitement spécial d'assert a été mentionné. Voici d'autres types d'exceptions qui bénéficient d'un traitement spécial par le jvm:

  • NullPointerException
  • ArithmeticException.
  • StackOverflowException
  • Toutes sortes d'erreurs OutOfMemory
  • ...

Les exceptions ne sont pas spéciales, mais le jvm les utilise dans des cas particuliers, vous ne pouvez donc pas les implémenter vous-même sans écrire votre propre jvm. Je suis sûr qu'il existe des exceptions plus spéciales.


0

La plupart de ces classes ne sont pas vraiment implémentées avec l'aide «spéciale» du compilateur ou de la JVM. Object enregistre certains natifs qui fouillent dans les structures JVM internes, mais vous pouvez également le faire pour vos propres classes. (J'admets que cela est sujet à la sémantique, "appeler un natif défini dans la JVM" peut être considéré comme un support JVM spécial.)

Ce qui est / est / spécial est le comportement des instructions «nouvelles» et «lancées» dans la manière dont elles initialisent ces structures internes.

Les annotations et les chiffres sont cependant assez bizarres.


4
aioobe fait référence à des classes que vous ne pouvez pas implémenter vous-même, car elles ont un support spécial. Vous ne pouvez pas créer votre propre classe Object en tant que racine du système de types sans hériter du formulaire java.lang.Object. Object a un support spécial à la fois du compilateur et de jvm pour s'assurer qu'il s'agit d'une classe racine. Les appels natifs ne suffisent pas pour contourner ce problème.
josefx
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.