好久沒有更新過blog了。
回顧:
前面的一篇博客總結了:
- 九種基本數據類型的大小,以及他們的封裝類。
- Switch能否用string做參數?
- equals與==的區別。
- Object有哪些公用方法?
- Java的四種引用,強弱軟虛,用到的場景。
五個問題,並進行了相關的詳細解釋,也請大家多多發表見解,相互學習。
6. Hashcode的作用
作用:用於查找的快捷性
注意事項:
1.兩個對象通過 == 或 equals方法比較結果爲true的時候,這兩個對象的hashCode也一定要相同。所以重寫equals方法的時候建議重寫hashCode方法,保證結果一致;
2.兩個對象的hashCode相同不代表兩個對象完全相同。也就是說hashCode並不能用來控制和判斷兩個對象是否相同。
舉例
Class A{
public int age;
public int stature;
public String name;
public A (int age, int stature, String name){
this.age = age;
this.stature = stature;
this.name = name;
}
public A (){}
public getAge(){
return age;
}
public String getName(){
return name;
}
public int getStature(){
return stature;
}
@Override
public boolean equals(Object obj){
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A a = (A) obj;
if (a.getAge() != this.getAge())
return false;
if (a.getName() != null && !a.getName().equals(this.getName()))
return false;
if (a.getStature() != this.getStature())
return false;
return true;
}
@Override
public int hashCode(){
return name.leng() + stature + age;
}
}
1.equals方法和 == 比較結果爲true, hashCode也要相同
A a = new A(1, 175, “uana”);
A b = a;
b.equals(a); // b == a;2.equals方法比較結果爲true,hashCode結果也要一致
A a = new A(1, 175, “uana”);
A b = new A(1, 175, “uana”);
b.equals(a); // true3.hashCode相同不代表是同一個對象
A a = new A(1, 175, “uana”);
A b = new A(5, 170, “uana”);
b.equals(a); // false
b.hashCode() == a.hashCode(); // true
下面說一下使用hashCode怎麼樣提高查找速度(代碼中有些邏輯判斷不合理,大體思路已經表現出來)
public class MyHashMap {
/*根據hashCode存放數據,查詢數據的時候會減少查詢次數*/
private static Map<Integer, List<A>> map = new HashMap();
public static void put(A a) {
if (map.containsKey(a.hashCode())) {
if (!map.get(a.hashCode()).contains(a)) {
map.get(a.hashCode()).add(a);
}
} else {
List<A> list = new ArrayList<>();
list.add(a);
map.put(a.hashCode(), list);
}
}
public static A get(int hashCode, A target) {
if (map == null || map.size() == 0) {
return "";
}
if (map.get(hashCode).contains(target)) {
for (int i = 0; i < map.get(hashCode).size(); i++) {
if (target == map.get(hashCode).get(i)) {
// 有效減少查詢次數
return map.get(hashCode).get(i);
}
}
}
return "";
}
}
注:上面舉得例子是一個類(A)的情況下。同理還有可能出現不同類的對象的hashCode值是相同的情況。
總結:hashCode不同代表肯定不是同一個對象。它的作用是用來分離存儲對象的,通過hashCode值來存儲數據,在查找的時候能有效提高查詢速度。
7. 進程和線程
Part one 兩者的區別
對於應用層開發者而言,進程就是一個正在執行的(運行的)應用程序。線程就是進程內部的一個執行序列,一個進程可以有多個線程。線程依附於進程而存在。也可以把線程看做是一個輕量級的進程(實際上不是進程)。
Part two 創建線程的方式
1.繼承Thread類
2.實現Runnable接口
3.應用程序可以使用Executor框架來創建線程池
實現Runnable接口這種方式更受歡迎,因爲不需要繼承Thread類。因爲Java不支持多繼承,所以很多情況下在應用設計中會優先考慮使用Runnable接口。另外使用線程池也是一個很不錯的選擇。
Part three
線程的狀態
1.就緒狀態(Runnable): 線程準備運行,但是不代表立刻就能開始執行。
2.運行中(Running):進程正在執行線程中的代碼邏輯。
3.等待中(Waiting):線程處於阻塞狀態,等待外部的代碼邏輯處理結束。
4.睡眠中(Sleeping):線程被強制睡眠。
5.I/O阻塞(Blocked on I/O):等待I/O操作完成。
6.同步阻塞狀態(Blocked on Synchronization):此刻線程在等待獲取到鎖。
7.死亡(Dead):線程執行結束。
注意事項:不建議手動調用stop來結束線程(這樣操作不安全,所以不建議這樣操作。可以考慮在線程執行中加入邏輯控制來結束線程)。
8.如何做線程同步
關鍵詞:synchronized
實際應用中的作用點:
1.修飾實例方法,作用與當前實例加鎖。進入同步代碼前要獲取當前實例的鎖
2.修飾靜態方法,作用於當前類對象加鎖,進入同步代碼前要獲得當前類對象的鎖
3.修飾代碼塊。指定加鎖對象,對給定的對象加鎖,進入同步代碼塊之前要獲得給定對象的鎖
下面出相應的例子:代碼中會標註注意點
public class NormalMothedSync implements Runnable{
// 共享資源
static int num = 0;
/**
* synchronized 修飾實例方法
*/
public synchronized void increase(){
num++;
}
@Override
public void run(){
for(int i=0; i<1000; i++){
increase();
}
}
public static void main(String[] args) throws InterruptedException{
// 創建實體對象
NormalMothedSync nms = new NormalMothedSync();
// 注意:這裏兩個線程使用的runnable對象是同一個對象。感興趣的朋友可以試試,兩個線程的runnable不適用同一個對象試試結果
Thread th_01 = new Thread(nms);
Thread th_02 = new Thread(nms);
th_01.start();
th_02.start();
// join含義:當前線程B等待A線程終止之後才能執行(前提是AB兩個線程使用的鎖是同一個鎖對象)
th_01.join();
th_02.join();
// 輸出結果 2000
System.out.println(num);
}
}