單例類、 final修飾符、抽象類
單例類、 final修飾符、抽象類
單例類:
設計模式:是一種問題的解決思想。解決某一類問題最行之有效的方法。Java有23中設計模式。
單例設計模式:解決一個類在記憶體中只存在一個物件。
如果一個類始終只能建立一個例項,則這個類稱為單例(Singleton)類。
想要保證物件的唯一:
1.禁止其他程式自由建立物件:將構造方法私有化,使用private修飾。
2.為了讓其他程式可以訪問到該類物件,只能在本類定義一個物件:在類中建立一個本類物件。
3.為了方便其他程式對該物件的訪問,可以對外提供訪問方法:提供一個public方法可以獲取該物件。
兩種寫法:
1.餓漢式:不管你用不用,一開始就建立單例物件,即先初始化物件。
開發一般使用此寫法,安全性
private static Single s=new Single();
private Single(){}
public static Single getInstance(){
return s;
}
2.懶漢式:使用時才建立物件,是延遲載入。
private static Single1 s=null;
private Single1(){}
public static Single1 getInstance(){
if(s==null){
s=new Single1();
}
return s;
}
final修飾符:
final關鍵字可用於修飾類、變數和方法,用於表示它修飾的類、變數和方法不可改變。
final變數
final修飾變數時,表示該變數一旦獲得了初始值之後就不可被改變,final既可修飾成員變數(包括類變數和例項變數),也可以修飾區域性變數、形參。
final修飾成員變數
成員變數
類變數:當類初始化時,系統會為類變數分配記憶體,並賦預設值。
例項變數:當建立物件時,系統會為該物件的例項屬性分配記憶體,並賦預設值。
final修飾的類變數、例項變數能指定初始值的地方如下:
類變數:靜態初始化塊或宣告該屬性時指定初始值。
例項變數:非靜態初始化塊、宣告該屬性時或構造方法中指定初始值。
注意:例項屬性不能在靜態初始化塊中指定初始值,因為靜態初始化塊是靜態成員,不可訪問例項屬性—非靜態成員;類屬性不能在普通初始化塊中指定初始值,因為類屬性在類初始化階段已經被初始化了,普通初始化塊不能對其重新賦值。
例5.13 final成員的使用示例。
public class Test{
final int age;
{
System.out.println(age);//編譯出錯
age=6;
System.out.println(age);
}
public static void main(String[] args){
new Test();
}
}
注意:如果打算在構造方法、初始化塊中對final成員變數進行初始化,則不要在初始化之前就訪問成員變數的值。
final修飾區域性變數
使用final修飾區域性變數:
可以在定義時指定預設值,則後面程式碼中不能再對該變數賦值。
如果在定義時沒有指定預設值,則可在後面程式碼中對該final變數賦初始值,但只能一次,不能重複賦值。
注意:test方法的形參用final修飾,則該形參由系統根據傳入的引數來完成初始化。
final修飾基本型別和引用型別變數的區別
當用final修飾基本型別變數時,不能對基本型別變數重新賦值,即基本型別變數的值不能被改變
引用型別變數儲存的是一個引用,final只保證這個引用(地址)不會改變,即一直引用同一個物件,但這個物件可以發生改變。
final方法
final修飾的方法不可被重寫,如果出於某些原因,不希望子類重寫父類的某個方法,則可以使用final修飾該方法。
例5.16 final方法舉例。
public class TestFinalMethod{
public final void test(){}
}
class Sub extends TestFinalMethod{
public void test(){}----->出現編譯錯誤
}
final修飾的方法僅僅是不能被重寫,並不是不能被過載。
final類
final修飾的類不可有子類。例如,java.lang.Math類就是一個final類,它不可以有子類。
例5.17 編寫程式,演示final修飾的類不可被繼承。
public final class FinalClass{
//類中成員
}
class Sub extends FinalClass{------------->將出現編譯錯誤
}
抽象類:
抽象方法
基類中定義的方法,有時候只有在派生類中才能寫出方法體。
Java中,這種沒有方法體的方法稱為抽象方法。
抽象方法宣告格式:
[修飾符] abstract 返回值型別 方法名([形式引數表]);
抽象方法的特點
抽象方法的返回值型別前有關鍵字abstract;
抽象方法沒有方法體;
抽象方法的定義是一行單獨語句,以分號結束;
在抽象方法宣告中使用static修飾符是錯誤的。
抽象類
類中如果定義了抽象方法,這個類必須定義為抽象類。
[public] abstract class 類名{
//類體(屬性、非抽象方法、抽象方法、構造方法)
//類體(初始化塊、內部類、列舉類)
}
抽象類不能建立自己的物件,使用new建立抽象類物件將產生錯誤。
子類繼承抽象類時,應該覆蓋抽象類中的所有抽象方法,否則子類也必須定義為抽象類。
注意
含有抽象方法的類(包括直接定義了一個抽象方法;繼承了一個抽象父類,但沒有完全實現父類包含的抽象方法)只能被定義成抽象類。但抽象類中卻並一定包含抽象方法。
抽象方法和空方法體的方法不是同一個概念
public abstract void test(); 是一個抽象方法,它根本沒有方法體,即方法定義後面沒有一對花括號
public void test(){}一個普通方法,定義了方法體,只是方法體為空,因此這個方法不可以使用abstract來修飾
例5.18 抽象類示例。
public abstract(抽象類,不能例項化的) class Shape{
public abstract double calcArea()(抽象方法
);
public Shape(){}構造方法不用於建立Shape物件,而是用於被子類呼叫
public Shape(String name){
System.out.println(name+ " Shape Created");
}
public String toString(){
System.out.println(“this is Shape!”);
}
}
public class Circle extends Shape{
public float r;
private final float PI=3.14;
public Circle(String name,float r){
super(name);
this.r=r;
}
public float calcArea()(子類Circle,必須重寫Shape類中的抽象方法 ,否則Circle就是一個抽象類
){
return PI*r*r;
}
}
注意
final和abstract永遠不能同時使用。
abstract不能用於修飾屬性,不能用於修飾區域性變數,即沒有抽象變數、沒有抽象屬性等說法;abstract也不能用於修飾構造方法,沒有抽象構造方法。抽象類裡定義的構造方法只能是普通構造方法。
static和abstract不能同時修飾某個方法,即沒有所謂的類抽象方法。
abstract關鍵字修飾的方法必須被其子類重寫才有意義,否則這個方法將永遠不會有方法體,因此abstract方法不能定義為private訪問許可權。
抽象類的作用
程式碼重用--子類可以重用抽象父類中的屬性和非抽象方法;
規劃--抽象類中通過定義抽象方法規劃了其所有子類必須要實現的功能,或者說指定了其子類物件與外界的互動介面,因為抽象方法的方法頭部分已經規定了該方法將來被子類物件呼叫的格式。
模板模式的設計
模板模式:抽象類作為多個子類的通用模板,子類在抽象類的基礎上擴充套件、改造,但子類總體上會保留抽象類的行為方式。
抽象類不能例項化,但抽象類可作為變數的型別和方法形參型別,可將抽象類子類的物件賦給該變數或做方法的實參。例如,
Shape s=new Rectangle();
public static String ShowShapinfo(Shape item){
if(item instanceof Rectangle){
Rectangle r=(Rectangle)item; //其他程式碼
}
}