類在繼承時,會用到this和super,以前也不多用到,之前看過,今天看了一下,只記得之前看過,理解仍是不深。html
thisjava
直接引用,至關於指向對象自己算法
型參與成員變量名字相同,用this來區分bash
class A{
private int number = 15;
A(){
System.out.println("number:"+number);
}
public int getNumber(int number){
this.number = number; //用來區分參數number和A類中的屬性number(this.number)
return this.number;
}
}
複製代碼
引用構造函數多線程
this(參數):調用本類中另外一種構造函數(應在構造函數的第一行)ide
super函數
直接引用,指向當前對象的父類,能夠用super.xx來引用父類的屬性ui
子類的變量/方法與父類的變量/方法重名this
在子類種調用時,重名的方法/變量,直接使用是子類的,this.xx或this.xx()屬於調用父類的。spa
引用構造函數
super(參數):調用父類中某種構造函數(應在構造函數的第一行)
這兩個方法都是Object中帶有的方法,即全部方法都有equals和hashcode方法。
在沒有重寫的狀況下,equals方法即"==",hashcode方法獲取哈希碼,即肯定對象在散列表中的索引位置。
若是不重寫equals方法,那麼好比User這種對象,通常咱們equals比較的是它包含的屬性是否相同,不重寫的話,依照Object的equals方法,兩個對象的內存地址不一樣,因此返回false,這顯然不是咱們想要要的。因此要重寫,在方法中判斷屬性是否相同。
若是隻重寫equals方法,而沒有重寫hashcode方法,好比User對象放在hashset中,hashset的特性是不容許重複。當咱們放入兩個數據相同的User時,重寫後的equals方法返回true,可是沒有重寫hashcode方法,依照Object的hashcode方法,兩個對象的hash值不一樣,因此不是同一對象,hashset中均可以存入,可是當咱們將User放入hashset中,要求若是是要求數據不一樣的話,就會沒法實現。因此須要重寫hashcode方法,使得包含數據相同的兩個User對象,返回的hash值相同,而此時,hashset會判斷重複,就只能存入一個。
```
而這其中就涉及到hashset判斷重複的依據
add(object)會先用Object的equals方法和hashcode方法判斷set中,
是否已有重複元素,固然,若是兩個元素若是不是指向同一對象,不管如何也不會重複。
因此,當咱們須要剔除數據相同的元素,就須要在此基礎上從新給元素對應的類型重寫hashcode方法。
```
複製代碼
參考:
重寫equals方法後重寫hashCode方法的必要性
如何重寫hashCode算法
HashSet重複元素判斷
對我來講,是急需增強的一個點,由於以前用到的很少,因此也就不求甚解。
Java多線程的兩種實現方式:繼承Thread類、實現Runnable接口
繼承Thread類
package cn.wh3t;
public class MultiThread extends Thread{
private String name;
public MultiThread(String name) {
// TODO 自動生成的構造函數存根
this.name = name;
}
@Override
public void run() {
// TODO 自動生成的方法存根
for(int i =0;i<5;i++) {
System.out.println("Thread-"+name+"----hello"+i);
}
}
public static void main(String[] args) {
MultiThread multiThread1 = new MultiThread("A");
MultiThread multiThread2 = new MultiThread("B");
multiThread1.start();
System.out.println("hello1");
System.out.println("hello2");
multiThread2.start();
System.out.println("hello3");
System.out.println("hello4");
}
}
複製代碼
輸出結果://屢次運行結果都會不一樣
hello1
hello2
Thread-A----hello0
Thread-A----hello1
Thread-A----hello2
hello3
Thread-A----hello3
hello4
Thread-A----hello4
Thread-B----hello0
Thread-B----hello1
Thread-B----hello2
Thread-B----hello3
Thread-B----hello4
複製代碼
實際啓動的時候並非調用Thread的run方法,而是strat方法。
那麼run()和start()有什麼區別
在Java中,線程一般都有5種狀態:建立、就緒、運行、阻塞、死亡
1. 建立:生成線程對象時,還未調用start方法
2. 就緒:調用了該線程對象的start,線程進入就緒狀態,可是並未把該線程設成當前線程。在線程運行以後,從等待或者睡眠中回來,也會進入就緒狀態
3. 運行:將該線程設爲當前線程,線程進入運行狀態,開始運行run()中的代碼
4. 阻塞:線程正在運行時,被暫停,一般是爲了某個時間發生或者加載某個資源以後再繼續運行。sleep、suspend、wait都會形成阻塞
5. 死亡:線程的run()結束,或者調用了stop方法,線程就會死亡。對於死亡的線程,再使用start方法也不會使其進入就緒狀態
總之就是說,若是沒有start方法,只有run方法。就不是多線程執行了。由於start方法使線程進入就緒狀態,並無當即執行,經過上面代碼的運行結果也能夠看出,線程1的start要早於hello一、hello2的打印,卻比他們輸出要晚。若是沒有start,只是run(),就會依次執行,迴歸單線程(當前主線程)執行的狀態。
實現Runnable接口
package cn.wh3t;
public class MultiThreadByRunnable implements Runnable{
private int count = 20;
@Override
public void run() {
// TODO 自動生成的方法存根
for(int i =0;i<40;i++) {
if(count>0) {
System.out.println(Thread.currentThread().getName()+" "+count--);
}
}
}
public static void main(String[] args) {
MultiThreadByRunnable runnable = new MultiThreadByRunnable();
Thread thread1 = new Thread(runnable,"A");
Thread thread2 = new Thread(runnable,"B");
thread1.start();
System.out.println("hello1");
System.out.println("hello2");
thread2.start();
System.out.println("hello3");
System.out.println("hello4");
}
}
複製代碼
輸出結果://屢次運行結果都會不一樣
hello1
A 20
hello2
A 19
A 18
A 17
hello3
hello4
A 16
B 15
B 13
B 12
A 14
B 11
B 10
B 9
B 8
B 6
B 5
B 4
B 3
B 2
B 1
A 7
複製代碼
兩種實現方式不一樣:相比之下,實現Runnable接口更有優點
1. 適合多個代碼相同的程序去處理同一資源;
2. 能夠避免Java中的單繼承,能夠擴展實現更多接口
3. 增長程序的健壯性,代碼能夠被多個程序共享,代碼和數據獨立
sleep()、suspend()、yield()等都是Thread類的方法,wait()和notify()確實屬於Object的方法,即全部類均可以執行這兩個方法。由於這兩個方法阻塞時要釋放佔用的鎖,而全部對象都有鎖。wait()致使線程阻塞,釋放該對象上佔用的鎖。調用notify()則致使因調用該對象的wait()而阻塞的線程中,隨機選擇一個解除阻塞(可是要等到真正得到鎖之後才能執行)。這兩個方法必須在synchronized方法或塊中執行,由於synchronized方法/塊才能佔有鎖,有鎖才能釋放。
關於wait和notify要注意的三個點:
1. 調用notify方法而接觸阻塞的線程是從wait方法阻塞的線程中隨機選取的,因此沒法預料哪一個線程被選取,因此要當心,避免不肯定性產生的問題
2. 除了notify,notifyAll方法也能夠喚醒,解除阻塞的是因wait方法而阻塞的全部線程,固然,只有得到鎖的那個線程才能進入可執行狀態
3. wait和notify必須成對存在
package cn.wh3t;
public class CountThread extends Thread{
int total;
@Override
public void run() {
// TODO 自動生成的方法存根
synchronized (this) {
for(int i=0;i<100;i++) {
total = total +1 ;
}
this.notify();//喚醒被阻塞的線程
System.out.println("notify"+total);
}
}
}
複製代碼
package cn.wh3t;
public class TestWaitAndNotify {
public static void main(String[] args) {
CountThread thread = new CountThread();
thread.start();
synchronized(thread) {
System.out.println("等到線程結束"+thread.total);
try {
thread.wait();
System.out.println("wait"+thread.total);
}catch(Exception e) {
e.printStackTrace();
}
System.out.println("計算的結果是:"+thread.total);
}
}
}
複製代碼
(主線程等待技術線程結束後纔打印輸出)
等到線程結束0
notify100
wait100
計算的結果是:100
複製代碼
參考:
java 線程詳解
Thread的run()與start()的區別
java thread中的wait()和notify()