JAVA程式設計基礎——類和物件(繼承、多型)
一、單利模式
(1)單例類只能有一個例項;
(2)單例類必須自己建立自己的唯一例項;
(3)單例類必須給所有其他物件提供這個例項。
場景:一個類可以定義無數個物件,但是隻有一個例項。
1、餓漢式單利模式
package practise.test1030; //餓漢式單利模式 class MySingleTon2{ private static MySingleTon2 singleTon = new MySingleTon2(); private MySingleTon2(){ System.out.println("MySingleTon2().init"); } //提供一個全域性的訪問點 public static MySingleTon2 getInstance(){ return singleTon; } } public class Test2 { public static void main(String[] args) { MySingleTon2 mySingleTon = MySingleTon2.getInstance(); MySingleTon2 mySingleTon2 = MySingleTon2.getInstance(); MySingleTon2 mySingleTon3 = MySingleTon2.getInstance(); MySingleTon2 mySingleTon4 = MySingleTon2.getInstance(); System.out.println(mySingleTon); System.out.println(mySingleTon2); System.out.println(mySingleTon3); System.out.println(mySingleTon4);//地址相同 } }
2、懶漢式單利模式
package practise.test1030; //懶漢式單利模式 class MySingleTon{ private static Object lock = new Object(); private static MySingleTon singleTon = null; private MySingleTon(){ System.out.println("MySingleTon().init"); } //提供一個全域性的訪問點 //可重入函式:執行緒安全的函式 靜態條件 臨界區程式碼段 原子性操作 加鎖 public static MySingleTon getInstance(){ //1 /** * 原子操作 * 多程序時,第一個程序還未來得及new一個物件,singleTon==null */ if(singleTon == null){ singleTon = new MySingleTon(); } //2 //單執行緒浪費空間 synchronized (lock){ if(singleTon == null){ singleTon = new MySingleTon(); } } //3 //多執行緒時至少執行兩次 if(singleTon == null){ synchronized (lock){ singleTon = new MySingleTon(); } } //4 雙重檢驗 (double-checked locking) if(singleTon == null){ synchronized (lock){ if(singleTon == null){ singleTon = new MySingleTon(); } } } return singleTon; } } public class Test1 { public static void main(String[] args) { MySingleTon mySingleTon = MySingleTon.getInstance(); MySingleTon mySingleTon2 = MySingleTon.getInstance(); MySingleTon mySingleTon3 = MySingleTon.getInstance(); MySingleTon mySingleTon4 = MySingleTon.getInstance(); System.out.println(mySingleTon); System.out.println(mySingleTon2); System.out.println(mySingleTon3); System.out.println(mySingleTon4);//地址相同 } }
3、靜態內部類實現單利模式
package practise.test1030; //靜態內部類實現單利模式 //只有訪問靜態內部類的時候,才會建立物件 class MySingleTon3{ private MySingleTon3(){ } private static class SingleTon{ private static MySingleTon3 single = new MySingleTon3(); } public static MySingleTon3 getInstance(){ return SingleTon.single; } } public class Test3 { public static void main(String[] args) { MySingleTon3 single = MySingleTon3.getInstance(); MySingleTon3 single2 = MySingleTon3.getInstance(); MySingleTon3 single3 = MySingleTon3.getInstance(); MySingleTon3 single4 = MySingleTon3.getInstance(); System.out.println(single); System.out.println(single2); System.out.println(single3); System.out.println(single4); } }
二、繼承
繼承是一種機制,可以進行程式碼的重用。在JAVA中,所有的繼承都是公有繼承。子類比超類擁有的功能更加豐富
基類(超類):
子類(派生類):
在通過擴充套件類定義子類的時候,僅需要指出子類與超類的不同之處。所以在設計類的時候應該將通用的方法放在超類,而將具有特殊用途的方法放在子類當中。
在子類中可以增加域、增加方法或覆蓋超類的方法,但是絕對不能刪除繼承的任何域和方法。
注:
關鍵字this有兩個用途:1、引用隱式引數;2、呼叫該類其他的構造器。
super關鍵字也有兩個用途:1、呼叫超類的方法;2、呼叫超類的構造器。
在呼叫構造器的時候,這兩個關鍵字的使用方式很相似:呼叫構造器的語句只能作為另一個構造器的第一條語句出現。構造引數既可以傳遞給本類(this)的其他構造器,也可以傳遞給超類(super)的構造器。
package practise.test1030;
//繼承
/**
* super關鍵字:
* super();——呼叫基類的建構函式
* super.data——訪問基類的資料成員
* super.func()——呼叫基類的成員方法
*/
/**
* 基類
*/
class Base{
public int ma;
public Base (int ma){
this.ma = ma;
}
//Base的靜態程式碼塊
static {
System.out.println("Base.static{}");
}
//Base的例項程式碼塊
{
System.out.println("Base.instance");
}
public void fun(){
System.out.println("Base.fun()");
}
public static void fun2(){
System.out.println("Base.fun2()");
}
}
/**
* 派生類
* 繼承父類除建構函式外的所有屬性
* 派生類構造物件的初始化順序
* 基類靜態
* 派生類靜態
* 基類例項
* 基類構造方法
* 派生類例項
* 派生類構造方法
*/
class Derieve extends Base {
private int mb;
public Derieve(int a,int b){
super(a);//必須放在第一行
this.ma = ma;
}
//Base的靜態程式碼塊
static {
System.out.println("Base.static{}");
}
//Base的例項程式碼塊
{
System.out.println("Base.instance");
}
public void fun(){
System.out.println("Base.fun()");
}
public static void fun2(){
System.out.println("Base.fun2()");
}
}
//ERROR
/**
* 繼承了ma,沒有繼承建構函式,
* 如何構造基類的資料成員???(呼叫基類的建構函式)
*/
/*class Derieve extends Base{
private int mb;
}*/
/**
* ERROR
* 派生類的建構函式只能構造派生類的資料成員,不能構造基類的資料成員
*
class Derieve extends Base {
private int mb;
public Derieve(int a,int b){
//ERROR ma = a;
this.mb = mb;
}
}*/
public class Test4 {
public static void main(String[] args) {
Base base = new Base(100);
Derieve derieve = new Derieve(111,222);//new物件 1、分配類存 2、
/**
* JAVA中只支援向上繼承
*/
base = derieve;
/**
* 基類和派生類之間的相互賦值
*/
/**
* 過載:overloade:函式名相同,引數列表不同,和返回值沒關係
* 並不一定是在同一個類當中,在繼承關係上也能構成過載
* 重寫(覆蓋)overwrite;函式名相同,引數列表相同,函式返回值相同
* 返回值不同能否構成過載:???
* 遵守協變型別——JAVA程式設計思想
*/
}
}
問題一:派生類繼承了父類除構造方法外的所有屬性。
問題二:super關鍵字:
super關鍵字:
(1)super();——呼叫基類的建構函式
(2)super.data——訪問基類的資料成員
(3)super.func()——呼叫基類的成員方法
問題三:派生類構造物件的初始化順序?
(1)基類靜態;
(2)派生類靜態;
(3)基類例項;
(4)基類構造方法;
(5)派生類例項;
(6)派生類構造方法。
package practise.test1030;
//(public)基類的資料成員在派生類中的訪問許可權
class Base1{
public int ma;
// public Base (int ma){
// this.ma = ma;
// }
//Base的靜態程式碼塊
static {
System.out.println("Base.static{}");
}
//Base的例項程式碼塊
{
System.out.println("Base.instance");
}
public void fun(){
System.out.println("Base.fun()");
}
public static void fun2(){
System.out.println("Base.fun2()");
}
}
//class Derieve1 extends Base {
//
//}
public class Test5 {
public static void main(String[] args) {
}
}
問題四:基類資料成員在派生類當中的訪問許可權:
同包子類 | 同包非子類 | 不同包子類 | 不同包非子類 | |
public | 可以 | 可以 | 可以 | 可以 |
private | / | / | / | / |
proctected | 可以 | 可以 | 可以 | / |
預設許可權 (包訪問許可權) |
可以 | 可以 | / | / |
問題五:過載和重寫(覆蓋):
(1)過載:overloade:函式名相同,引數列表不同,和返回值沒關係。
注:並不一定是在同一個類當中,在繼承關係上也能構成過載 。
(2)重寫(覆蓋)override:函式名相同,引數列表相同,函式返回值相同。
三、多型
多型:基類引用,引用了派生累物件,並且和派生類有同名的覆蓋方法。
JAVA實現多型有三個必要條件:繼承、重寫、向上轉型。
(1)繼承:在多型中必須存在有繼承關係的子類和父類;
(2)重寫:子類對父類中的某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法;
(3)向上轉型:在多型中,只有將子類的引用賦給父類物件,才能夠呼叫父類的方法和子類的方法。
問題六:建構函式內,能不能發生多型?
能
問題七:動多型和靜多型的理解:
(1)動多型:發生在執行的時候(過載);
(2)靜多型:發生在編譯的時候(重寫).
在JAVA只有兩種方式可以實現多型:繼承和實現介面。