1。概要
元のテキスト:https : //mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484210&idx=1&sn=9d40e2e4c72f0727c7b7925cbe314fc0&chksm=ebd74233dca0cb2560677c7dc7746cf166aedcab195dcab
実際、これはいくつかに要約できます。
registerNatives()【底层实现、不研究】
hashCode()
equals(Object obj)
clone()
toString()
notify()
notifyAll()
wait(long timeout)【还有重载了两个】
finalize()
オブジェクトには合計11のメソッドがあり、そのうちの1つは基礎となる実装registerNatives()で、そのうちの2つはwait()およびwait(long timeout、int nanos)のオーバーロードメソッドです。
だから私たちが実際に見る必要があるのは8つの方法です
属性がもう1つあります。
/**
* Returns the runtime class of this {@code Object}. The returned
* {@code Class} object is the object that is locked by {@code
* static synchronized} methods of the represented class.
*
* <p><b>The actual result type is {@code Class<? extends |X|>}
* where {@code |X|} is the erasure of the static type of the
* expression on which {@code getClass} is called.</b> For
* example, no cast is required in this code fragment:</p>
*
* <p>
* {@code Number n = 0; }<br>
* {@code Class<? extends Number> c = n.getClass(); }
* </p>
*
* @return The {@code Class} object that represents the runtime
* class of this object.
* @jls 15.8.2 Class Literals
*/
public final native Class<?> getClass();
equalsおよびhashCodeメソッド
qualsメソッドとhashCodeメソッドはインタビューの重要な質問であると言えますが、Stringの場合、インタビューの質問のどこにでもあると言えます。
まず、ObjectのequalsおよびhashCodeのネイティブ実装を見てみましょう。
ハッシュコード:
public native int hashCode();
等しい:
public boolean equals(Object obj) {
return (this == obj);
}
それらはすべて非常にシンプルに見えます:
hashCode()由native方法底层实现了。
equals()就直接==判断是否相等了。
彼らが何をしているかをより明確にするために、そのメモを読みましょう:
コメントによると、次の点を要約できます。
- equals()メソッドを書き換えるには、hashCode()メソッドを書き換える必要があります
- equals()メソッドは、==等価演算子を使用して、デフォルトでオブジェクトのアドレスを比較します
- hashCode()メソッドには、最下層がハッシュテーブルであるオブジェクトのパフォーマンスを向上させる機能があります。
- 同じオブジェクト(オブジェクトが変更されていない場合):繰り返しhashCode()を呼び出すと、返されるintは同じです!
- hashCode()メソッドは、デフォルトでオブジェクトのアドレスから変換されます
equals()メソッドにも5つのデフォルトの原則があります。
- Reflexivity—> Call equals()はtrueを返します。誰がこれら2つのオブジェクトでequals()を呼び出しても、trueを返します。
- 整合性—>オブジェクトが変更されない限り、複数の呼び出しの後に対応する結果が返されます。
- Transitivity—> x.equals(y)とy.equals(z)の両方がtrueを返すと、次の結果が得られます。x.equals(z)はtrueを返します
- 対称性-> x.equals(y)とy.equals(x)は等しくなければなりません。
- 入力パラメータがnullで、戻り値がfalseです
hashCode()がハッシュテーブルを最下層として使用してパフォーマンスを向上させる理由は簡単に理解できます。HashMapの挿入をもう一度見てみましょう。
ハッシュ値が等しくない場合は、キーが等しくないと直接判断できます!
equalsおよびhashCodeメソッドのオーバーライド
equals()メソッドはデフォルトでオブジェクトのアドレスを比較し、==等価演算子を使用します。しかし、私たちの通常の開発によると、オブジェクトのアドレスを比較しても意味がありません。
一般に、2つのAddressオブジェクトがある場合、これら2つのオブジェクトの州番号、都市番号、および番地が等しい限り、これら2つのオブジェクトは等しいと見なされます!
Stringによって実装されたequalsおよびhashCodeメソッド
最初に学んだときに聞いたことがあるかもしれません。Stringは、equalsメソッドとhashCodeメソッドを実装しています。
これが、String.equals()を直接使用して、2つの文字列が等しいかどうかを判断できる理由です。
その実装を見てみましょう:
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
toStringメソッド
次に、これも非常に簡単なtoStringメソッドを見てみましょう。
toStringメソッドは、主にオブジェクトを識別するために使用されます。
上記の結果から確認できます:結果には何も表示されません〜
そのため、通常はtoString()を書き換え、出力された結果はデバッグに非常に便利です。
@Override
public String toString() {
return "Address{" +
"provinceNo=" + provinceNo +
", cityNo=" + cityNo +
", streetNo=" + streetNo +
'}';
}
次の結果ははるかに良く見えます:
クローン方式
トップノートも見てみましょう:
上記のコメントを読んだ後、次の点を要約できます。
cloneメソッドはオブジェクトのクローン作成に使用されます。通常、クローンを作成するオブジェクトは独立しています(元のオブジェクトとは別です)。
ディープコピーは、オブジェクトのメンバー変数(変数参照の場合)を複製する必要があることを意味し、シャローコピーは、メンバー変数が複製されないことを意味します。
浅いコピーを見てみましょう。Employeeオブジェクトはコピーされていますが、そのメンバー変数hireは複製されていないため、同じDateオブジェクトを指しています!
クローンの使用
それでは、オブジェクトをどのようにクローンしますか?浅いコピーと深いコピーはどちらも2つのステップです。
- 複製されたオブジェクトはCloneableインターフェースを実装する必要があります
- クローンメソッドを書き換えます。できればパブリックに変更します。
浅いコピー:Personオブジェクトのみがコピーされますが、日付はコピーされません!
public class Person implements Cloneable {
// 可变的成员变量
private Date date;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
ディープコピー:Personオブジェクトだけでなく、日付メンバー変数もコピーします
public class Person implements Cloneable {
// 可变的成员变量
public Date date;
@Override
public Object clone() throws CloneNotSupportedException {
// 拷贝Person对象
Person person = (Person) super.clone();
// 将可变的成员变量也拷贝
person.date = (Date) date.clone();
// 返回拷贝的对象
return person;
}
}
4.2クローン質問のさらなる研究が保護されました
私と同じ質問がある人がいるかどうかはわかりません。
浅いコピーのみが必要ですが、オブジェクト.clone()を直接呼び出してそれを実現できますか?
たとえば、Addressオブジェクトができました。
public class Address {
private int provinceNo;
private int cityNo;
private int streetNo;
public Address() {
}
public Address(int provinceNo, int cityNo, int streetNo) {
this.provinceNo = provinceNo;
this.cityNo = cityNo;
this.streetNo = streetNo;
}
}
次のコードについてどう思いますか?
Address address = new Address(1, 2, 3);
address.clone();
私たちは皆知っています:
protected修饰的类和属性,对于自己、本包和其子类可见
あなたは考えるかもしれません:clone()メソッドはObjectクラスで定義され(protectedで変更)、カスタムのAddressオブジェクトは暗黙的にObjectを継承し(すべてのオブジェクトはObjectのサブクラスです)、次にサブクラスが呼び出しますObjectがclone()をprotectedで変更しても問題ありません
ただし、IDEの現実から、このコンパイルは失敗することがわかります。
私がすぐに思ったエラーの理由:保護された修飾子から逸脱しましたか?
保護された変更済みのクラスと属性は、自分自身、このパッケージとそのサブクラスに表示されます。この文自体は間違っていません。ただし、追加する必要があります。保護されたメンバーまたはメソッドの場合、分子クラスとスーパークラスが同じパッケージにあるかどうか。基本クラス同一个包中的子类
ではなく、访问自身从基类继承而来的受保护成员,而不能访问基类实例本身的受保护成员。
上記のコードは間違っています。AddressとObjectは同じパッケージ内になく、AddressはObjectのcloneメソッドに直接アクセスします。これは機能しません。
2つの写真を撮って見せます(写真を読んでから、上記の説明を読んだ後、理解できます)。
5、待機して通知するメソッド
待機および通知メソッドは、実際にはJavaがスレッド間の通信のために提供するAPIです。
いつものように、コメントの内容を見てみましょう。
待機方法:
通知方法:
notifyAll()メソッド:
上記のコメントを読んだ後、次の点を要約できます。
- wait、notify、notifyAll()のいずれであっても、リスナーオブジェクト(ロックオブジェクト)から呼び出す必要があります。
- 簡単に言うと、これらはすべて同期コードブロックで呼び出されます。そうしないと、例外がスローされます。
- Notify()は待機キュー内のスレッドを起動し(どのスレッドが起動するかは不明)、notifyAll()は待機キュー内のすべてのスレッドを起動します
- wait()のスレッドが起こされる4つの状況があります
- スレッドが中断されました
- wait()タイムアップ
- notify()によって起こされた
- notifyAll()によるウェイクアップ
- wait()を呼び出すスレッドはロックを解放します
実際、上記を要約した後は、それほど印象に残ることはありませんが、いくつかの質問に答えて、wait()とnotify()の理解を深めることができます。
Objectメソッドに待機して通知するのはなぜですか?
最初から言った:wait()とnotify()は、Javaがスレッド間の通信を提供するAPIです。これはスレッドなので、ThreadクラスではなくObjectクラスで何が定義されていますか? ?
私たちのため锁是对象锁
、すべてのオブジェクトがロックになることができます:[Javaのロック機構を理解するあなたは、学生が確認することができます忘れてしまった場合]。让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。
ロックオブジェクトは任意なので、これらのメソッドはObjectクラスで定義する必要があります
notifyメソッドが呼び出された後はどうなりますか?
上記のように、notifyは待機キュー内のスレッドを起こします。
ただし、次のことに注意してください。
notifyメソッドが呼び出された後、起こされたスレッドはすぐにロックオブジェクトを取得しません。代わりに、ロックされたオブジェクトは、通知の同期コードブロックが実行された後に取得されます。
睡眠と待機の違いは何ですか?
Thread.sleep()とObject.wait()はどちらも、現在のスレッドを一時停止してCPU制御を解放できます。
主な違いは、Object.wait()は、CPUを解放しながらオブジェクトロックの制御を解放することです。
そしてThread.sleep()はロックを解放しませんでした
参考資料:
https://blog.csdn.net/lingzhm/article/details/44940823
http://www.cnblogs.com/dolphin0520/p/3920385.html
https://www.cnblogs.com/eer123/p/7880789.html
https://www.jianshu.com/p/f4454164c017