L'objet est la classe parent de toutes les classes, c'est-à-dire que toutes les classes de Java sont héritées directement ou indirectement à partir de la classe d'objets. Par exemple, si vous créez une classe Classa, bien qu'elle ne soit pas explicitement indiquée, c'est la valeur par défaut d'ExtendSobject.
Les trois points suivants "..." indiquent que plusieurs paramètres incertains peuvent être acceptés. L'ancienne façon d'écrire est ObjectArgs [], mais il est recommandé d'utiliser ... dans la nouvelle version de Java. Par exemple
publicvoidgetSomething(String...strings)(){}
L'objet est la classe parent de toutes les classes de Java. C'est-à-dire que toutes les classes, qu'elles soient créées par elles-mêmes ou les classes du système, sont héritées de la classe d'objets, c'est-à-dire que toutes les classes peuvent remplacer la classe d'objets à n'importe quelle occasion. Selon le principe du remplacement de Rich, les sous-classes peuvent remplacer leur classe parent à n'importe quelle occasion, mais la classe parent ne peut pas nécessairement remplacer leur sous-classe. Ce qui est souvent dit dans Java, c'est en fait cette vérité! La classe d'objets incarne les quatre principales caractéristiques du polymorphisme, de l'héritage, de l'encapsulation et de l'abstraction dans l'idée OOP!
La classe d'objets est la classe de base de toutes les classes, pas un type de données. Vous pouvez interroger le document JDK pour comprendre cela, toutes les classes sont héritées de l'objet.
Objet ... Objets Cette définition de paramètre est une manifestation polymorphe dans le cas de paramètres de méthode incertains. Autrement dit, cette méthode peut transmettre plusieurs paramètres, et le nombre de ces paramètres est incertain. De cette façon, vous devez effectuer un traitement correspondant dans le corps de la méthode. Parce que l'objet est une classe de base, utilisez un formulaire de paramètre tel que l'objet ... objets, permettant à tous les objets hérités de l'objet sous forme de paramètres. Cette méthode doit être utilisée relativement rarement dans la pratique.
La forme de l'objet [] Obj est une forme de paramètre composée d'un tableau d'objet. Cela signifie que les paramètres de cette méthode sont fixes et sont un tableau d'objets. Quant aux éléments stockés dans ce tableau, ils peuvent être des objets hérités de toutes les classes d'objet.
Il est recommandé de lire ces choses de base plusieurs fois de plus "Thinkinjava"
L'objet de Java est la classe parent de toutes les autres classes. Du point de vue de l'héritage, c'est la racine de niveau supérieur, c'est donc également la seule classe sans classe parent. Il contient certaines méthodes couramment utilisées pour les objets, tels que GetClass, HashCode, égal, clone, tostring, notifier, attendre et d'autres méthodes couramment utilisées. Par conséquent, après que d'autres classes héritent de l'objet, ils peuvent implémenter ces méthodes sans implémentation répétée. La plupart de ces méthodes sont des méthodes natives et l'analyse détaillée suivante est effectuée.
Le code principal est le suivant:
Objet de classe publique {private static native void registerNatives (); static {registerNatives ();} public final class native <?> getClass (); public native int hashcode (); public boolean equals (objet obj) {return (this == obj);} protected objet natif clone () throw getClass (). getName () + "@" + Integer.tohexString (hashcode ());} public final native void notify (); public final void void notifyall (); public final void void wait (long timeout) lance l'interruption IllégalArgumentException ("La valeur de tempsort est négative");} if (nanos <0 || nanos> 999999) {lancez new illégalargumentException ("Nanos Second Timeout Value Out of Range" {wait (0);} Protected void finalize () lève le jetable {}}Méthode des inscriptions
Étant donné que la méthode de registre est modifiée par un bloc statique, la méthode sera exécutée lorsque la classe d'objets sera chargée. La méthode locale correspondante est java_java_lang_object_registernatives, comme suit,
Jniexport void jnicalljava_java_lang_object_registerNatives (jnienv * env, jclass CLS) {(* Env) -> RegisterNatives (Env, CLS, méthodes, sizeof (méthodes) / sizeof (méthodes [0]));}Vous pouvez voir qu'il appelle indirectement la méthode de la structure JninativeInterface_, qui peut être simplement considérée comme celle-ci: ce qu'il fait correspond probablement au nom de la méthode de la couche Java avec la fonction locale, afin que le moteur d'exécution puisse appeler les fonctions C / C ++ basées sur ces tables de relation correspondantes lors de l'exécution de byteCode. Comme indiqué ci-dessous, enregistrez ces méthodes. Lorsque le moteur d'exécution exécute la méthode HashCode, il peut trouver la fonction JVM_IHASHCODE de JVM via la table de relation. () Je peux également savoir que les types sur la couche Java doivent être convertis en type int. Ce mappage peut en fait être considéré comme mappant une chaîne à un pointeur de fonction.
Méthodes statiques jninativemethod [] = {{"hashcode", "() i", (void *) & jvm_ihashcode}, {"wait", "(j) v", (void *) & jvm_monitorwait}, {"notify", "()", (void *) & jvm_monitory "() V", (void *) & jvm_monitornotifyall}, {"clone", "() ljava / lang / object;", (void *) & jvm_clone},}; Méthode GetClass
La méthode GetClass est également une méthode locale, et la méthode locale correspondante est java_java_lang_object_getclass, comme suit:
Jniexport jclass jnicalljava_java_lang_object_getclass (jnienv * env, jobject this) {if (this == null) {jnu_thrownullpointerException (env, null); retour 0; } else {return (* env) -> getObjectClass (Env, this); }}Nous examinons donc principalement la fonction GetObjectClass. La classe correspondante dans la couche Java dans la couche C ++ est Klassoop, de sorte que les métadonnées et les informations de méthode sur la classe peuvent être obtenues à travers elle.
Jni_entry (jclass, jni_getObjectClass (jnienv * env, travail obj)) jniwrapper ("getObjectClass"); Dtrace_probe2 (hotspot_jni, getObjectClass__entry, env, obj); klassoop k = jnihandles :: résolu_non_null (obj) -> klass (); jclass ret = (jclass) jnihandles :: make_local (env, klass :: cast (k) -> java_mirror ()); Dtrace_probe1 (hotspot_jni, getObjectClass__Return, ret); retourne ret; Jni_endMéthode HashCode
D'après la méthode des registres de registres précédents, enregistrez plusieurs méthodes locales, nous pouvons voir que la fonction correspondant à la méthode HashCode est jvm_ihashcode, c'est-à-dire,
Jvm_entry (jint, jvm_ihashcode (jnienv * env, manche de travail)) jvmwrapper ("jvm_ihashcode"); // comme implémenté dans la machine virtuelle classique; Retour 0 Si l'objet est null return handle == null? 0: ObjectSynchronizer :: fasthashcode (thread, jnihandles :: résolu_non_null (manche)); jvm_endLa logique générée pour HashCode est déterminée par la fonction get_next_hash de synchronizer.cpp. La mise en œuvre est relativement complexe. Il existe différentes stratégies de génération basées sur différentes valeurs de HashCode, et enfin un masque de hachage est utilisé pour le traiter.
static inline intptr_t get_next_hash (thread * self, oop obj) {intptr_t value = 0; if (hashcode == 0) {value = os :: random ();} else if (hashcode == 1) {intptr_t addRbits = intptr_t (obj) >> 3; value = addrbits ^ (addRrbits >> 5) ^ Gvars.stwrandom;} else if (hashcode == 2) {value = 1; // pour les tests de sensibilité} else if (hashcode == 3) {value = ++ gvars.hcSequence;} else if (hashcode == 4) {value = intptr_t (obj);} else {non signé t = sel 11). ; Self -> _ hashStatew = v; value = v;} value & = markoopdes :: hash_mask; if (value == 0) value = 0xbad; assert (value! = Markoopdes :: no_hash, "invariant"); tevent (hashcode: generate); return value;} égal à la méthode
Il s'agit d'une méthode non locale, et la logique de jugement est très simple, et c'est directement == comparaison.
méthode de clone
Dans le tableau de la méthode locale, nous savons que la fonction locale correspondant à la méthode du clone est jvm_clone. La méthode de clone implémente principalement la fonction de clonage de l'objet et génère le même nouvel objet en fonction de l'objet (les attributs de l'objet de notre classe commune cloneront la valeur s'il est un type primitif, mais s'il s'agit d'un objet, l'adresse de l'objet sera clonée). Pour implémenter le clonage des classes Java, vous devez implémenter l'interface clonable. If (! Klass-> is_clonable ()) Vérifiera si l'interface est implémentée. Déterminez ensuite si l'espace mémoire est alloué dans deux situations. Le nouvel objet est new_obj, puis la structure de données de la couche Copie et C ++ sont définies pour new_obj. Enfin, il sera converti en type de travail en type d'objet de couche Java.
Jvm_entry (jobject, jvm_clone (jNienv * env, manche de travail)) jvmwrapper ("jvm_clone"); manche obj (thread, jnihandles :: résolve_non_null (manche)); const klasshandle klass (thread, obj-> klass ()); jvmTivmoboBRe ; {const int longueur = ((arrayoop) obj ()) -> longueur (); new_obj = collectecyheap :: array_allocy (klass, size, longueur, check_null);} else {new_obj = collectecyheap :: obj_allocate (klass, size, check_null);} copy :: conjoint_jlongs_atoM ((jlong *);) (jlong *) new_obj, (size_t) align_object_size (size) / heapwordsperlong); new_obj-> init_mark (); barrières * bs = univers :: heap () -> barrier_set (); assert (bs-> has_write_region_opt (), "Barrier set n'a pas eu write_region "); bs-> write_region (mecregion ((tasword *) new_obj, size)); if (klass-> has_fininalizer ()) {assert (obj-> is_instance ()," devrait être instanceoop "); new_obj = instanceklass :: register_finalizer (instanceoop (new_obj), check_null);} JniHandles :: Make_local (Env, OOP (new_obj)); jvm_endméthode de tostring
La logique consiste à obtenir le nom de classe plus @ plus HexaDecimal HashCode.
Méthode de notification
Cette méthode est utilisée pour réveiller le thread et les instructions de modification finales ne peuvent pas être réécrites. La méthode locale correspondante est jvm_monitornotify. ObjectSynchronizer :: Notify appellera éventuellement ObjectMonitor :: notify (traps). Ce processus est que ObjectSynchronizer essaiera d'obtenir l'objet FreeObjectMonitor dans le thread actuel et essaiera de l'obtenir du global s'il échoue.
JVM_ENTRY (void, jvm_monitornotify (jNienv * env, manche de travail)) jvmwrapper ("jvm_monitornotify"); Manipuler obj (thread, jnihandles :: résolu_non_null (manche)); affirmer (obj-> is_instance () || obj-> is_array (), "jvm_monitornotify doit s'appliquer à un objet"); ObjectSynchronizer :: Notify (obj, check); Jvm_endL'objet ObjectMonitor contient un objet de file d'attente _WaitSet, qui contient tous les threads dans l'état d'attente et est représenté par l'objet ObjectWaitter. Ce qui doit faire est d'obtenir d'abord le verrouillage de la file d'attente _WaitSet, puis de supprimer le premier objet ObjectWaitter dans la file d'attente _WAITSET, puis de traiter l'objet en fonction de différentes stratégies, telles que l'ajout à la file d'attente _Entrylist. Libérez ensuite le verrouillage de la file d'attente _WaitSet. Il ne libère pas le verrouillage correspondant de synchronisé, de sorte que le verrou ne peut être libéré que jusqu'à ce que le bloc de synchronisation synchronisé soit terminé.
void ObjectMonitor :: notify (traps) {check_owner (); if (_waitSet == null) {tevent (vide-notify); return;} dtrace_monitor_probeee (notify, this, object (), thread); int stratégie = knob_movenotifyee; iterator = dequeuewaitter (); if (iterator! = null) {tevent (notify1 - transfert); garantie (iterator-> tstate == objectwaitter :: ts_wait, "invariant"); garantie (iterator -> _ notifié == 0, "invariant"); if (stratégie! = 4) {iterator-> tstate = ObjectWaitter :: ts_enter;} iterator -> _ notifié = 1; objetwaitter * list = _entrylist; if (list! = Null) {assert (list -> _ prev == null, "invariant"); assert (list-> tstate == objectwaitter :: ts_enter, "invariant"); assert (list! = Ivator, "invator ;} if (stratégie == 0) {// prend to entryListIf (list == null) {iterator -> _ next = iterator -> _ pré-= iterator;} else {list -> _ prev = iterator; iterator -> _ Next = list; iterator -> _ Précédent = null; _entrylist = iterator;}} à EntryListif (list == null) {iterator -> _ next = iterator -> _ prev = null; _entryList = iterator;} else {// Considérez: trouver la queue nécessite actuellement une marche à temps linéaire de // la liste d'entrée. Nous pouvons rendre l'accès à la queue constant en constante-temps en convertissant à // un CDLL au lieu d'utiliser notre Dll.ObjectWail * Tail; pour (Tail = List; Tail -> _ Next! = NULL; Tail = Tail -> _ Next); Assert (Tail! = Null && Tail -> _ Next == NULL, "INVARIANT"); Itherator; = Null;}} else if (politique == 2) {// prend to cxq // prend to cxqif (list == null) {iterator -> _ next = iterator -> _ prev = null; _entrylist = iterator;} else {iterator-> tstate = objectwaiter :: ts_cxq; _cxq; iterator -> _ next = front; if (atomic :: cmpxchg_ptr (iterator, & _cxq, front) == front) {break;}}}} else if (politique == 3) {// append to cxqiterator-> tstate = objectwaiter :: ts_cxq; pour (; _cxq; if (tail == null) {iterator -> _ next = null; if (atomic :: cmpxchg_ptr (iterator, & _cxq, null) == null) {break;}} else {while (tail -> _ Next! = null) tail = tail -> _ Next; tail -> _ Next = itorator; ; iterator -> _ next = null; break;}}} else {parkevent * ev = iterator -> _ event; iterator-> tstate = objectwaitter :: ts_run; orderAccess :: Fence (); ev-> un uncark ();} if (politique <4) {iterator-> wait_reenter_begin (this); La file d'attente d'attente, pas la liste d'entrée. Nous pourrions // déplacer l'opération Add-To-Entrylist, ci-dessus, en dehors de la section critique // protégé par _WaitSetlock. Dans la pratique, ce n'est pas utile. À l'exception // des délais d'attente et interrompre le propriétaire du moniteur // est le seul thread qui saisit _WaitSetlock. Il n'y a presque pas de contenu // sur _WaitSetLock, il n'est donc pas rentable de réduire la durée de la section // critique.} Thread :: SpinRelease (& _waitSetLoc); if (iterator! = Null && objectitor :: _ sync_notifications! = Null) {objectMonitméthode notifyall
Semblable à la méthode de notification, il est simplement que lorsque vous avez récupéré la file d'attente _WAITSET, ce n'est pas le premier mais tout.
Méthode d'attente
La méthode d'attente fait attendre le fil. Sa méthode locale correspondante est jvm_monitorwait, qui appelle indirectement objectynchronizer :: attendre, ce qui correspond à notifier. Il s'agit également de la méthode d'attente correspondant à l'appel de l'objet ObjectMonitor. Cette méthode est longue et ne sera pas publiée ici. Il s'agit probablement de créer un objet ObjectWaitter, puis d'obtenir le verrouillage de la file d'attente _WAITSET et d'ajouter l'objet ObjectWaitter à la file d'attente, puis de libérer le verrouillage de la file d'attente. De plus, il libérera le verrouillage correspondant de synchronisé, de sorte que le verrou n'attend pas que le bloc de synchronisation synchronisé soit terminé.
Jvm_entry (void, jvm_monitorwait (jnienv * env, manche de travail, jlong ms)) jvmwrapper ("jvm_monitorwait"); Manipuler obj (thread, jnihandles :: résolu_non_null (manche)); affirmer (obj-> is_instance () || obj-> is_array (), "jvm_monitorwait doit s'appliquer à un objet"); JavathreadinObjectWaitState jtiows (thread, ms! = 0); if (jvmtiexport :: devrait_post_monitor_wait ()) {jvmtiexport :: post_monitor_wait ((javathread *) thread, (oop) obj (), ms); } Objectynchronizer :: wait (obj, ms, check); jvm_endFinaliser la méthode
Cette méthode est utilisée pour être appelée lorsque l'objet est recyclé. Ceci est soutenu par le JVM. La méthode finalisée de l'objet ne fait rien par défaut. Si la sous-classe doit effectuer un traitement logique lorsque l'objet est recyclé, la méthode finalisée peut être remplacée.
Résumer
Ce qui précède est tout le contenu de cet article sur l'exemple d'analyse de Java de l'objet du point de vue du code source JDK. J'espère que ce sera utile à tout le monde. Les amis intéressés peuvent continuer à se référer à d'autres sujets connexes sur ce site. S'il y a des lacunes, veuillez laisser un message pour le signaler. Merci vos amis pour votre soutien pour ce site!