オブジェクトは、すべてのクラスの親クラスです。つまり、Javaのすべてのクラスは、オブジェクトクラスから直接または間接的に継承されます。たとえば、クラスを作成する場合、明示的に述べられていませんが、それはextendobjectのデフォルトです。
次の3つのポイント「...」は、いくつかの不確実な数のパラメーターを受け入れることができることを示しています。古い執筆方法はObjectArgs []ですが、Javaの新しいバージョンで使用することをお勧めします。例えば
publicvoidgetSomething(String...strings)(){}
オブジェクトは、Javaのすべてのクラスの親クラスです。つまり、すべてのクラスは、それ自体が作成されているか、システム内のクラスが作成されているかどうかにかかわらず、オブジェクトクラスから継承されます。つまり、すべてのクラスはあらゆる機会にオブジェクトクラスを置き換えることができます。リッチの代替の原則によれば、サブクラスはどんな機会でも親クラスを置き換えることができますが、親クラスは必ずしもサブクラスを置き換えるとは限りません。 Javaでよく言われることは、実際にはこの真実です!オブジェクトクラスは、OOPアイデアにおける多型、相続、カプセル化、および抽象化の4つの主要な特性を具体化します!
オブジェクトクラスは、データ型ではなく、すべてのクラスのベースクラスです。 JDKドキュメントをクエリしてこれを理解できます。すべてのクラスはオブジェクトから継承されます。
オブジェクト...オブジェクトこのパラメーター定義は、不確実なメソッドパラメーターの場合の多型症状です。つまり、この方法は複数のパラメーターを渡すことができ、これらのパラメーターの数は不確かです。このようにして、メソッド本体で対応する処理を行う必要があります。オブジェクトはベースクラスであるため、オブジェクトなどのパラメーター形式を使用して、オブジェクトからパラメーターとして継承されたすべてのオブジェクトを許可します。この方法は、実際には比較的まれに使用する必要があります。
オブジェクト[] OBJの形式は、オブジェクト配列で構成されるパラメーター形式です。これは、このメソッドのパラメーターが固定されており、オブジェクト配列であることを意味します。この配列に保存されている要素については、オブジェクトのすべてのクラスから継承されるオブジェクトにすることができます。
これらの基本的なことを「thinkinjava」をさらに読むことをお勧めします
Javaのオブジェクトは、他のすべてのクラスの親クラスです。継承の観点から見ると、それはトップレベルのルートであるため、親クラスのない唯一のクラスでもあります。 GetClass、HashCode、Equals、Clone、ToString、Notify、Wait、その他の一般的に使用される方法など、オブジェクトに一般的に使用されるいくつかの方法が含まれています。したがって、他のクラスがオブジェクトを継承した後、繰り返し実装せずにこれらのメソッドを実装できます。これらの方法のほとんどはネイティブの方法であり、次の詳細な分析が行われます。
メインコードは次のとおりです。
public class object {private static native void Registernatives(); static {RegisterNatives();} public final Native Class <? getClass()。getName() + "@" + integer.tohexstring(hashcode());} public final native void notify(); public final native void notifyall(); public final native void wait(long timeout)throws interrupedexception; public final boid wait(long nanos、intedexedexepteception {) IllegalargumentException( "Timeout Value Is Negative");} if(nanos <0 || nanos> 999999){新しいIllegalargumentexception( "Nanos 2番目のタイムアウト値からの範囲") void fanize()スロースロー可能{}}登録済み方法
登録解除法は静的ブロックによって変更されるため、オブジェクトクラスがロードされるとメソッドが実行されます。対応するローカル方法は、java_java_lang_object_registernativesです。
jniexport void jnicalljava_java_lang_object_registernatives(jnienv *env、jclass cls){( *env) - > registernatives(env、cls、methods、sizeof(methods [0]);}JninativeInterface_構造のメソッドを間接的に呼び出すことがわかります。これは単にこれと見なすことができます。それが行うことは、おそらく局所関数を使用してJavaレイヤーのメソッド名に対応しているため、実行エンジンがBytecodeを実行するときにこれらの対応する関係テーブルに基づいてC/C ++関数を呼び出すことができます。以下に示すように、これらの方法を登録してください。実行エンジンがハッシュコードメソッドを実行すると、関係テーブルを介してJVMのJVM_IHASHCODE関数を見つけることができます。 ()Java層のタイプをINTタイプに変換する必要があることもわかります。このマッピングは、実際に文字列を関数ポインターにマッピングすると見なすことができます。
static jninativemethodメソッド[] = {{"hashcode"、 "()i"、(void *)&jvm_ihashcode}、{"wait"、 "(j)v"、(void *)&jvm_monitorwait}、{"notify"、 " "()v"、(void *)&jvm_monitornotifyall}、{"clone"、 "()ljava/lang/object;"、(void *)&jvm_clone}、}; GetClassメソッド
GetClassメソッドもローカルメソッドであり、対応するローカル方法はjava_java_lang_object_getclassです。
jniexport jclass jnicalljava_java_lang_object_getclass(jnienv *env、jobject this){if(this == null){jnu_thrownullpointerexception(env、null); 0を返します。 } else {return(*env) - > getobjectclass(env、this); }}したがって、ここでは、主にgetobjectclass関数を見ています。 C ++レイヤーのJava層の対応するクラスはKlassoopであるため、クラスに関するメタデータとメソッド情報をそれを通して取得できます。
jni_entry(jclass、jni_getobjectclass(jnienv *env、job obj))jniwrapper( "getobjectclass"); dtrace_probe2(hotspot_jni、getobjectclass__entry、env、obj); klassoop k = jnihandles :: resolve_non_null(obj) - > klass(); jclass ret =(jclass)jnihandles :: make_local(env、klass :: cast(k) - > java_mirror()); dtrace_probe1(hotspot_jni、getobjectclass__return、ret); rett; jni_endを返します
ハッシュコードメソッド
以前のRegisterNativesメソッドからいくつかのローカルメソッドを登録すると、ハッシュコード法に対応する関数はjvm_ihashcodeであることがわかります。
jvm_entry(jint、jvm_ihashcode(jnienv* env、job handle))jvmwrapper( "jvm_ihashcode"); //クラシック仮想マシンに実装されているように。 return 0オブジェクトがnull return handle == nullの場合? 0:objectSynchronizer :: fasthashcode(thread、jnihandles :: resolve_non_null(handle)); jvm_end
ハッシュコード用に生成されたロジックは、synchronizer.cppのget_next_hash関数によって決定されます。実装は比較的複雑です。ハッシュコードのさまざまな値に基づいてさまざまな生成戦略があり、最後にハッシュマスクを使用して処理します。
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; valy addrbits ^(addrbits ^( gvars.stwrandom;} else if(hashcode == 2){value = 1; //感度テストの場合<< 11); self-> _ hashstatex = self-> _ hashstatey; self> _ hashstatey = self-> _ hashstatez; self> _ hashstatez = self> _ hashstatew; unsigned v = self-> _ hashstatew; v =(v ^(v >> 19) ^(t>(t>)) ; self-> _ hashstatew = v; value = vメソッドに等しい
これは非ローカルな方法であり、判断ロジックは非常に単純であり、直接==比較です。
クローンメソッド
ローカルメソッドテーブルから、クローンメソッドに対応するローカル関数はjvm_cloneであることがわかります。クローンメソッドは主にオブジェクトのクローン関数を実装し、オブジェクトに基づいて同じ新しいオブジェクトを生成します(共通クラスのオブジェクトの属性は、原始タイプの場合は値がクローンされますが、オブジェクトの場合、オブジェクトのアドレスはクローン化されます)。 Javaクラスのクローニングを実装するには、クローン可能なインターフェイスを実装する必要があります。 if(!klass-> is_cloneable())は、インターフェイスが実装されているかどうかを確認します。次に、メモリ空間が2つの状況で割り当てられるかどうかを判断します。新しいオブジェクトはnew_objで、次にnew_objに設定されています。最後に、ジョブタイプにJavaレイヤーオブジェクトタイプに変換されます。
jvm_entry(jobject、jvm_clone(jnienv* env、job handle))jvmwrapper( "jvm_clone"); handle obj(thread、jnihandles :: resolve_non_null(ハンドル)); (!klass-> is_cloneable()){resourcemark rm(thread); throw_msg_0(vmsymbols :: java_lang_clonenotsupportedexception()、klass-> external_name();} const int size = obj-> size() int length =((arrayoop)obj()) - > length(); new_obj = collectedheap :: array_allocate(klass、size、length、check_null);} else {new_obj = collectedheap :: obj_allocate(klass、size、check_null);} cop (jlong*)new_obj、(size_t)align_object_size(size) / heapwordsperlong); new_obj-> init_mark(); barrierSet* bs = visiverse :: heap() - > barier_set(); assert(bs-> has_write_region_opt()、barrierセットはありません。 write_region "); bs-> write_region(memregion((heapword*)new_obj、size)); if(klass-> has_finalizer()){assert(obj-> is_instance()、" be instanceoop "); jnihandles :: make_local(env、ooop(new_obj)); jvm_endToStringメソッド
ロジックは、クラス名をプラス @ Plus Hexadecimalハッシュコードを取得することです。
通知方法
この方法は、スレッドの目覚めに使用され、最終的な変更命令を書き直すことはできません。対応するローカルメソッドはjvm_monitornotifyです。 ObjectSynchronizer :: Notifyは最終的にObjectMonitor :: Notify(TRAPS)を呼び出します。このプロセスでは、ObjectSynchronizerが現在のスレッドでFreeObjectMonitorオブジェクトを取得しようとし、失敗した場合はグローバルから取得しようとします。
jvm_entry(void、jvm_monitornotify(jnienv* env、job handle))jvmwrapper( "jvm_monitornotify");ハンドルobj(スレッド、jnihandles :: resolve_non_null(handle)); assert(obj-> is_instance()|| obj-> is_array()、 "jvm_monitornotifyはオブジェクトに適用する必要があります"); objectsynchronizer :: notify(obj、check); jvm_end
ObjectMonitorオブジェクトには、待機状態のすべてのスレッドを保持し、ObjectWaiterオブジェクトで表される_waitsetキューオブジェクトが含まれています。 Notifyが行う必要があるのは、最初に_waitsetキューロックを取得し、_waitsetキューで最初のObjectWaiterオブジェクトを削除し、_EntryListキューに追加するなど、さまざまな戦略に従ってオブジェクトを処理することです。次に、_waitsetキューロックを解放します。同期の対応するロックはリリースされないため、同期化された同期ブロックが終了するまでロックを解放できます。
void objectmonitor :: notify(traps){check_owner(); if(_waitset == null){tevent(empty -notify);} dtrace_monitor_probe(notify、this、this、this、object); int policy = nob_movenotifeee iterator = dequeuewaiter(); if(iterator!= null){tevent(notify1-transfer);保証(iterator-> tstate == objectwaiter :: ts_wait、 "Invariant");保証(iterator-> _ notified == 0、 "Invariant"); ObjectWaiter :: ts_enter;} iterator-> _ notified = 1; objectwaiter * list = _entrylist; if(list!= null){assert(list-> _ prev == null、 "Invariant"); assert(list-> tstate == objectwaiter :: ts_enter "; ;} if(policy == 0){// EntryListif(list == null){iterator-> _ next = iterator-> _ prev = iterator;} else {list-> _ prev = iterator; iterator-> _ next = list; iterator-> _ pret = null; _entrylist = iterator; _ entrist = iterator; EntryListif(list == null){iterator-> _ next = iterator-> _ prev = null; _entrylist = iterator;} else {//を追加するには、現在、テールを見つけるには//エントリリストの線形時間ウォークが必要です。 We can make tail access constant-time by converting to// a CDLL instead of using our current DLL.ObjectWaiter * Tail ;for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;assert (Tail != NULL && Tail->_next == NULL, "invariant") ;Tail->_next = iterator ;iterator->_prev = Tail ;iterator->_next = null;}} else if(policy == 2){// cxqへのprepend // cxqif(list == null){iterator-> _ next = iterator-> _ prev = null; _entrylist = iterator;} else {iterator-> tstate = objectwaiter::ts_cxxq; _cxq; iterator-> _ next = front; if(atomic :: cmpxchg_ptr(iterator、&_cxq、front)== front){break;}}}} else if(policy == 3){// cxqiterator-> tstate = objectwaiter::ts_waiter::ts_waiter::ts_waiter::ts_waiter::ts_waiter::ts_waiter = objecter = objecter: _cxq; if(tail == null){iterator-> _ next = null; if(atomic :: cmpxchg_ptr(iterator、&_cxq、null)== null){break;}} ; iterator-> _ next = null; break;}}} elles {parkevent * ev = iterator-> _ event; iterator-> tstate = objectwaiter :: ts_run; orderaccess :: fence(); ev-> upark();} if(ポリシー<4){iterator-> wait_reenter_begin(thiserer_begin(エントリリストではなく、待機キューを保護します。 //上記、_waitsetlockによって保護されているクリティカルセクションの外側で、上記の追加エントリリスト操作を移動できます。実際にはそれは役に立たない。 wait()タイムアウトの//例外を使用すると、モニターの所有者//は_waitsetlockをつかむ唯一のスレッドです。 _waitsetlockにはほとんどコンテンツがありません。//クリティカルセクションの長さを短縮することは有益ではありません。notifyallメソッド
Notifyメソッドと同様に、_waitsetキューを取得するとき、それは最初のものではなくすべてです。
待機方法
待機方法により、スレッドが待機します。対応するローカルメソッドはjvm_monitorwaitです。これは、objectsynchronizer :: waitを間接的に呼び出します。これは通知に対応します。また、ObjectMonitorオブジェクトを呼び出すことに対応する待機方法でもあります。この方法は長く、ここには投稿されません。おそらく、ObjectWaiterオブジェクトを作成し、_Waitsetキューロックを取得して、objectWaiterオブジェクトをキューに追加してから、キューロックを解放することです。さらに、同期の対応するロックが放出されるため、同期化された同期ブロックが終了するまでロックは待機しません。
jvm_entry(void、jvm_monitorwait(jnienv* env、job handle、jlong ms))jvmwrapper( "jvm_monitorwait");ハンドルobj(スレッド、jnihandles :: resolve_non_null(handle)); assert(obj-> is_instance()|| obj-> is_array()、 "jvm_monitorwaitはオブジェクトに適用する必要があります"); javathreadinobjectwaitstate jtiows(thread、ms!= 0); if(jvmtiexport :: shold_post_monitor_wait()){jvmtiexport :: post_monitor_wait((javathread *)スレッド、(oop)obj()、ms); } objectsynchronizer :: wait(obj、ms、check); jvm_endメソッドを完成させます
この方法は、オブジェクトがリサイクルされたときに呼び出されるために使用されます。これはJVMによってサポートされています。オブジェクトのファイナライズ方法は、デフォルトでは何もしません。オブジェクトがリサイクルされたときにサブクラスが論理処理を実行する必要がある場合、ファイナライズメソッドをオーバーライドできます。
要約します
上記は、JDKソースコードの観点からのJavaのオブジェクトの例分析に関するこの記事のすべての内容です。私はそれが誰にでも役立つことを願っています。興味のある友人は、このサイトの他の関連トピックを引き続き参照できます。欠点がある場合は、それを指摘するためにメッセージを残してください。このサイトへのご支援をありがとうございました!