一、super() 方法的用法及作用?
有如下Java類:
- public class Bird{
- private String name;
- public Bird() { }
- public Bird(String name){ this.name = name; }
- public void walk() { System.out.println(“走路”); }
- public String getName(){ return name; }
- public void setName(String name){ this.name = name; }
- }
另有一個類Chicken繼承上邊的Bird類;
- public class Chicken extends Bird{
- private String crest;
- public Chicken(){ super(); }
- public Chicken(String name,String crest) {
- super(name);
- this.name = name; }
- ………….
- }
在第二個自定義的類Chicken中,super()方法一共出現了兩次,分別是super()和super(name),請問super() 是什麼含義,放在這裡又作何解釋?
參考答案:
1.子類的構造過程中必須調用父類的構造方法。
2.子類可在自己的構造方法中使用super()來調用父類的構造方法。
(1)使用this來調用本類的另外的構造方法。
(2)如果調用super必須寫在子類構造方法的第一行。
3.如果子類的構造方法中沒有顯示的調用父類的構造方法,則系統默認的調用父類的無參的構造方法。
4.如果子類的構造方法中既沒有顯示調用父類的構造方法,而父類中又沒有無參的構造方法,則編譯出錯。
那你這裡第一個super()無參的就是調用了上面Bird類的Bird() 方法!
super(name)這個有參數就是調用public Bird(String name){
this.name = name; 這個方法!super() 是調用父類的構造函數,你例子中有Bird()和Bird(String name)兩個方法,super()是調用Bird()構造函數,而super(name)是調用Birth(String name)構造函數。注意super() 調用的是對應參數個數和類型相同的父類構造函數。 public Chicken(String name,String crest) { super(name); this.name = name; } 應該重復了吧,super(name)應該就是this.name = name。
二、Java 語言中的 volatile 和synchronized有什麼區別?
Java 語言中的 volatile 變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,並且運行時開銷也較少,但是它所能實現的功能也僅是 synchronized 的一部分。
我們知道,在Java中設置變量值的操作,除了long和double類型的變量外都是原子操作,也就是說,對於變量值的簡單讀寫操作沒有必要進行同步。
這在JVM 1.2之前,Java的內存模型實現總是從主存讀取變量,是不需要進行特別的注意的。而隨著JVM的成熟和優化,現在在多線程環境下volatile關鍵字的使用變得非常重要。
在當前的Java內存模型下,線程可以把變量保存在本地內存(比如機器的寄存器)中,而不是直接在主存中進行讀寫。這就可能造成一個線程在主存中修改了一個變量的值,而另外一個線程還繼續使用它在寄存器中的變量值的拷貝,造成數據的不一致。
要解決這個問題,只需要像在本程序中的這樣,把該變量聲明為volatile(不穩定的)即可,這就指示JVM,這個變量是不穩定的,每次使用它都到主存中進行讀取。一般說來,多任務環境下各任務間共享的標志都應該加volatile修飾。
Volatile修飾的成員變量在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。而且,當成員變量發生變化時,強迫線程將變化值回寫到共享內存。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。
Java語言規范中指出:為了獲得最佳速度,允許線程保存共享成員變量的私有拷貝,而且只當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對比。
這樣當多個線程同時與某個對象交互時,就必須要注意到要讓線程及時的得到共享成員變量的變化。
而volatile關鍵字就是提示VM:對於這個成員變量不能保存它的私有拷貝,而應直接與共享成員變量交互。
使用建議:在兩個或者更多的線程訪問的成員變量上使用volatile。當要訪問的變量已在synchronized代碼塊中,或者為常量時,不必使用。
由於使用屏蔽掉了VM中必要的代碼優化,所以在效率上比較低,因此一定在必要時才使用此關鍵字。
注意:聲明為volatile的簡單變量如果當前值由該變量以前的值相關,那麼volatile關鍵字不起作用,也就是說如下的表達式都不是原子操作:
- n = n + 1;
- n++;
如果要想使這種情況變成原子操作,需要使用synchronized關鍵字,如上的代碼可以改成如下的形式:
- public static synchronized void inc()
- {
- n++;
- }
將n=n+1改成了inc(),其中inc方法使用了synchronized關鍵字進行方法同步。因此,在使用volatile關鍵字時要慎重,並不是只要簡單類型變量使用volatile修飾,對這個變量的所有操作都是原來操作,當變量的值由自身的上一個決定時,如n=n+1、n++等,volatile關鍵字將失效,只有當變量的值和自身上一個值無關時對該變量的操作才是原子級別的,如n = m + 1,這個就是原級別的。所以在使用volatile關鍵時一定要謹慎,如果自己沒有把握,可以使用synchronized來代替volatile。
三、什麼是互斥鎖?使用互斥鎖都有哪些注意事項?
1.男孩和女孩例子,每個女孩是一個對象,每個男孩是個線程。每個女孩都有自己的鎖池。每個男孩可能在鎖池裡等待。
- Class Girl{
- Public void hand(){
- }
- Public syncronized void kiss(){
- }
- }
- Class Boy extends Thread{
- Public void run(){
- }
- }
鎖標記如果過多,就會出現線程等待其他線程釋放鎖標記,而又都不釋放自己的鎖標記供其他線程運行的狀況。就是死鎖。
死鎖的兩種處理方法:統一排列鎖順序(解決不同方法中對多個共享資源的訪問)。
對象1的方法
synchronized(a) synchronized(b)
對象2的方法
- synchronized(a)
- synchronized(b)
2.線程間通信(也就是線程間的相互協調)
線程間通信使用的空間稱之為對象的等待池(wait pool),該隊列也是屬於對象的空間的。
進入等待池
使用Object類中wait()的方法,在運行狀態中,線程調用wait(),此時表示線程將釋放自己所有的鎖標記和CPU的占用,同時進入這個對象的等待池。等待池的狀態也是阻塞狀態,只不過線程釋放自己的鎖標記。
退出等待池進入鎖池
notify():將從對象的等待池中移走一個任意的線程,並放到鎖池中,那裡的對象一直在等待,直到可以獲得對象的鎖標記。
notifyAll():將從等待池中移走所有等待那個對象的線程並放到鎖池中,只有鎖池中的線程能獲取對象的鎖標記,鎖標記允許線程從上次因調用wait()而中斷的地方開始繼續運行。
注意:只能對加鎖的資源進行wait()和notify()。
1) wait():交出鎖和CPU的占用;
2) notify():將從對象的等待池中移走一個任意的線程,並放到鎖池中,那裡的對象一直在等待,直到可以獲得對象的鎖標記。
3) notifyAll(): 將從等待池中移走所有等待那個對象的線程並放到鎖池中,只有鎖池中的線程能獲取對象的鎖標記,鎖標記允許線程從上次因調用wait()而中斷的地方開始繼續運行。
注:在Java.io包中Vector 和 HashTable 之所以是線程安全的,是因為每個方法都有synchronized修飾。Static 方法可以加 synchronized , 鎖的是類對象。
但是Vector 是 jdk 1.0 的 ArrayList 是 jdk1.2 所以實際應用還是使用ArrayList
例子:
生產者和消費者
一個櫃台一定數量的產品,櫃台滿時不能生產,空時不能夠買。
四、Java中流的分類都有哪些?
1)從數據類型分為字節流和字符流
字節流類:
抽象父類: InputStream,OutputStream
實現類包括如下幾種:
BufferedInputStream 緩沖流-過慮流 BufferedOutputStream ByteArrayInputStream 字節數組流-節點流 ByteArrayOutputStream DataInputStream 處理Java標准數據流-過慮流 DataOutputStream FileInputStream 處理文件IO流-節點流 FileOutputStream FilterInputStream 實現過慮流-字節過慮流父類 FilterOutputStream PipedInputStream 管道流 PipedOutputStream PrintStream 包含print() 和 println() RandomAccessFile 支持隨機文件
抽象父類:Reader, Writer
實現類:
BufferedReader BufferedWriter PrintWriter CharArrayReader CharArrayWriter FileReader FileWriter FilterReader FilterWriter InputStreamReader OutputStreamWriter PipedReader PipedWriter StringReader StringWriter
2) 從數據方向分為輸入流和輸出流
InputXXXXX , OutputXXXXX
3) 從流的功能分為節點流和過濾流
節點流用來傳輸數據。
過濾流用來封裝節點流或者其他過濾流,從而給節點流或其他的過濾流增加一個功能。
五、Java中父類和子類關系
父類的非私有化屬性(不同包的子類無法訪問default修飾符)和方法可以默認繼承到子類。
- Class Son extends Father{
- }
而如果父類中的私有方法被子類調用的話,則編譯報錯。
父類的構造方法子類不可以繼承,更不存在覆蓋的問題。
所以子類構造方法默認調用父類的無參構造方法。(所以養成寫無參構造的習慣)
如果子類訪問父類的有參構造方法,必須在子類構造方法第一行使用super(參數)
當構造一個對象的時候,系統先構造父類對象,再構造子類對象。
- Public class BMWcar extends Car{
- Public BMWcar(){
- Super(int alength); //顯式的調用父類的構造,默認調用無參構造
- //所以父類沒有無參構造的話,子類如果不加顯示調用其他構造就會報錯。這裡的super是一個對父類的引用
- }
- }