1. 程式人生 > 其它 >面向物件(下)--static/final/程式碼塊/抽象/介面/內部類

面向物件(下)--static/final/程式碼塊/抽象/介面/內部類

目錄

1 關鍵字:static

2 理解main方法的語法

3 類的成員之四:程式碼塊

4關鍵字:final

5 抽象類與抽象方法

6 介面(interface)

7 類的成員之五:內部類

static

功能

  1. 含義:靜態的

  2. 可以用來修飾屬性、方法、程式碼塊、內部類

  3. 使用static修飾屬性:表示靜態變數(類變數),沒有static的為例項變數,如果建立了類的多個物件,多個物件共享同一個靜態變數,當通過某一個物件修改靜態變數時,會導致其他物件呼叫此靜態變數時是修改過的

靜態變數的其他說明:

  • 靜態變數隨著類的載入而載入,早於物件的建立,和類一樣只會載入一次,在記憶體中存在一份
  • 可以通過類.靜態變數的方式進行呼叫,而例項變數不能這樣呼叫
  • 記憶體解析:
  1. 靜態方法:類似靜態變數,可以通過類之間呼叫,隨著類載入,只能呼叫靜態的方法或屬性,對於非靜態方法中,既可以呼叫非靜態方法或屬性,也可以呼叫靜態方法或屬性
  2. 注意點:
  • 靜態的方法內,不能使用this關鍵字、super關鍵字
  • 關於靜態屬性和靜態方法的使用,可以從生命週期的角度理解
  1. 開發中,如何確定一個屬性是否要宣告為static?
  • 如果屬性是可以被多個物件所共享的,不會隨著物件的不同而不同,如銀行賬戶類中的利率屬性

  • 類中的常量也常常宣告為static

      開發中,如何確定一個屬性是否要宣告為static?
    
  • 操作靜態屬性的方法,通常設定為static

  • 工具類中的方法,習慣宣告為static。比如Math、Arrays、Collections,不需要new物件即可直接用類呼叫方法

應用

class Circle{
    private double radius;
    private int id;
    
    public Circle(){
    	id=init++;//可以實現每次建立自動生成連續的id
   		total++;
	}
    public Circle(double radius){
    	this();//先呼叫一次上面的構造器,不用重複
        this.radius=radius;
	}
	private static int init=1001;
    private static total;
}

單例設計模式

採取一定的方法保證整個軟體系統中某個類只存在一個物件例項,且該類只提供一個取得其物件例項的方法

餓漢式

public class SingletonTest1{
    public static void main(String[] args){
    Bank bank1=Bank.getInstance();    
    Bank bank2=Bank.getInstance(); //此時bank1==bank2成立   
    }
}
class Bank{
    //1.私有化類的構造器
    private Bank(){
        
    }
    //2.內部建立類的物件,要求此物件宣告為靜態
    private static Bank instance=new Bank();
    //3.提供公共方法,返回類的物件
    public static Bank getInstance(){
        return instance;
    }
}

懶漢式

public class SingletonTest1{
    public static void main(String[] args){
    Order order1=Bank.getInstance();    
    Order order2=Bank.getInstance(); //此時bank1==bank2成立   
    }
}
class Order{
    //1.私有化類的構造器
    private Order(){
        
    }
    //2.內部建立類的物件,要求此物件宣告為靜態
    private static Order instance=null;
    //3.提供公共方法,返回類的物件
    public static Order getInstance(){
        if(instance==null){
            instance=new Order();
        }
        return instance;
    }
}

區分餓漢式和懶漢式

餓漢式:物件載入時間過長(缺點),是執行緒安全的(優點)

懶漢式:延遲物件的建立(優點),目前的寫法執行緒不安全,多執行緒內容時可以修改

使用場景

只生成一個例項,減少了系統性能開銷,當一個物件的產生需要比較多資源時,可以直接產生一個單例物件,永久駐留記憶體

  1. 網站計數器,為了保證同步
  2. 應用程式的日誌應用,因為日誌檔案一般一直處於開啟操作,便於追加
  3. 資料庫連線池,一個池子可以同時進行n個連線, 連線池固定一個
  4. 讀取配置檔案的類
  5. Application類
  6. windows工作管理員、回收站等

理解main方法的使用

  1. main()方法作為程式的入口
  2. main()也是一個普通的靜態方法
  3. 可以作為我們與控制檯互動的方式,之前是使用Scanner

類的成員四:程式碼塊

相當於對屬性賦值多了一種方式,實際上使用頻率不高

  1. 程式碼塊作用:用於初始化類、物件
  2. 程式碼塊如果有修飾,只能使用static
  3. 分類:靜態程式碼塊 非靜態程式碼塊
  4. 靜態程式碼塊:
  • 內部可以有輸出語句
  • 隨著類的載入而執行;
  • 用於初始化類的資訊;
  • 如果一個類中定義了多個靜態程式碼塊,則按照宣告的先後順序執行;
  • 靜態程式碼塊的執行要優先於非靜態程式碼塊的執行
  1. 非靜態程式碼塊:
  • 內部可以有輸出語句
  • 隨著物件的建立(new)而執行
  • 每建立一個物件就執行一次
  • 作用是可以在建立物件時,對物件的屬性等進行初始化
  • 如果一個類中定義了多個非靜態程式碼塊,則按照宣告先後順序執行
  1. 屬性賦值的執行順序

預設初始化--顯式初始化/程式碼塊中賦值--構造器中初始化--物件.屬性或物件.方法賦值

final關鍵字

  1. final可以修飾的結構:類、方法、變數
  2. final類:此類不能被其他類繼承,如String、System、StringBuffer
  3. final方法:不允許被重寫,比如Object中getClass
  4. final變數:此時的變數稱為是一個常量,不允許改變
  • 允許的賦值位置有:顯示初始化,程式碼塊中初始化、構造器中初始化
  1. final區域性變數:尤其是使用final修飾形參時,表明此形參是常量,呼叫此方法時給該形參賦值,之後方法中只能使用不能重新賦值
  2. static final修飾屬性:全域性常量,介面中屬性全是全域性常量
  3. 用途:一般方法不常使用,屬性有時需要final

抽象類與抽象方法

abstract意為抽象的,用來修飾結構、類、方法

抽象類

abstract修飾類:抽象類,此類不能例項化

  • 抽象類中一定有構造器,便於子類例項化時呼叫
  • 一般開發中都會提供子類

抽象方法

  • 只有方法的宣告,沒有方法體
  • 包含抽象方法的類必須是抽象類,但抽象類中可以沒有抽象方法
  • 若子類重寫了父類所有抽象方法後,子類方可例項化
abstract class Person{
    public abstract void eat();
}

使用上的注意點

  • abstract不能用來修飾屬性、構造器等結構
  • 不能用來修飾私有方法、靜態方法、final方法

建立抽象類的匿名子類

//Person定義為抽象類,Worker/Student為Person的子類
Worker worker=new Worker();
method(worker);//非匿名類非匿名物件

method(new Student()); //非匿名類匿名物件

//建立了一各匿名子類的非匿名物件:p
Person p=new Person(){
    @override
    public void eat(){//抽象類的子類必須重寫其中的抽象方法
        
    }
} 
//建立匿名子類的匿名物件
method(new Person(){
    @override
    public void eat(){//抽象類的子類必須重寫其中的抽象方法
        
    }
})

模板方法設計模式

public class TemplateTest{
    SubTemplate t=new SubTemplate();
    t.spendTime();
}
abstract class Template{
    //計算某段程式碼執行花費的時間
    public void spendTime(){
        long start=System.currentTimeMillis();
        code();//不確定的,易變的部分
        long end=System.currentTimeMillis();
        System.out.println("花費的時間為"+(end-start));
    }
    public abstract void code();
}
class SubTemplate extends Template{
    @override
    public void code(){
		System.out.println("sss");
        })
    }
}

介面

  • 有時需要從幾個類派生出一個子類,java不支援多重繼承,類無法滿足這個條件。
  • 有時需要從幾個類提取共同行為特徵,但又沒有is-a關係,只是有相同的行為特徵。如大學生中學生都是學生,跨欄運動員籃球運動員都是運動員,他們都具有學習的技能,一方面他們已經有父類,另一方面他們與技能不滿足子父類關係,因此可以把技能定義為介面

介面的使用

  1. 介面使用interface來定義

  2. java中,介面和類是並列的兩個結構

  3. 如何定義介面:定義介面中的成員

    3.1 JDK7及以前:介面中只能定義全域性常量和抽象方法

    全域性常量:public static final(即使省略這幾個詞依然是全域性常量)

    抽象方法:public abstract(即使省略這幾個詞依然是抽象方法)

    介面中不能定義構造器!!意味著介面不可以例項化

    3.2 JDK8以後 除了全域性常量和抽象方法還可以定義靜態方法和預設方法

  4. Java開發中,介面通過讓類去實現(Implements)的方法來使用

    如果實現類重寫了介面中所有抽象方法,則此實現類可以例項化

    如果沒有覆蓋所有抽象方法,則此實現類仍為抽象類

  5. java類可以實現多個介面,打破了類的單繼承性的侷限性,多個介面用implements A,B即可

  6. 介面與介面間可以繼承,且可以多繼承

  7. 介面的具體使用體現的多型性,介面實際上可以看做一種規範

package com.atguigu.ex1;

public class test {
	 
}
interface Flyable{
	public static final int MAX_SPEED=7900;
	int MIN_SPEED=7900;
	public abstract void fly();
	void stop();
}
//重寫全部抽象方法 可以例項化
class plane implements Flyable{
	@Override
	public void fly() {
		System.out.println("起飛");
		
	}
	@Override
	public void stop() {
		System.out.println("停止");
		
	}
}
//未重寫全部抽象方法 必須為抽象類
abstract class Kite implements Flyable{
	@Override
	public void fly() {
		// TODO Auto-generated method stub
		
	}
}
//介面間多繼承
interface AA{
	
}
interface BB{
	
}
interface CC extends AA,BB{
	
}

代理模式

應用場景:

安全代理:遮蔽對真實角色的直接訪問

遠端代理:通過代理類處理遠端方法呼叫

延遲載入:先載入輕量級代理物件,需要再載入真實物件

分類:

靜態代理

動態代理

工廠設計模式

實現了建立者與呼叫者的分離,即將建立物件的具體過程遮蔽起來,達到提高靈活性的目的

簡單工廠模式,定義一個實現類物件的工廠類XXXFactory,包含getXXX等功能但是增加產品時需要對現有程式碼進行修改,違反了開閉原則

工廠方法模式,定義一個工廠介面,N個工廠類實現工廠介面,即可

Java8介面新特性

除了定義全域性常量和抽象方法以外,還可以定義靜態方法、預設方法

靜態方法

1.介面中定義的靜態方法,只能通過介面呼叫

2.通過實現類的物件,可以呼叫介面中的預設方法

3.如果子類(或實現類)繼承的父類和實現的介面中聲明瞭同名同參數的方法,那麼子類沒重寫時,預設呼叫父類該方法(類優先原則)
但屬性不允許重名

4.如果實現類實現了多個介面,而多個介面中定義了同名同參數預設方法,那麼實現類沒有重寫此方法時報錯(介面衝突),這就需要在實現類中重寫此方法

public class SubclassTest {
	public static void main(String[] args) {
		Subclass s=new Subclass();
		//s.method1(); 介面的實現類呼叫會報錯
		//1.介面中定義的靜態方法,只能通過介面呼叫
		CompareA.method1();
		//2.通過實現類的物件,可以呼叫介面中的預設方法
		s.method2();
		s.method3();
	}
}
package com.atguigu.ex1;
public interface CompareA{
	public static void method1() {
		System.out.println("method1");
	}
	public default void method2() {
		System.out.println("method1");
	}
	default void method3() {
		System.out.println("method1");
	}
}

內部類

一個類定義於另一個類的內部,稱為內部類,反之為外部類

  1. 內部類一般用在定義它的類或語句塊內,外部引用時必須給出完整的名稱
  2. 內部類分類:成員內部類(靜態、非靜態) 區域性內部類(方法內、程式碼塊內、構造器內)
  3. 成員內部類:可以呼叫外部類的結構;可以定義屬性、方法、構造器等;可以被final、abstract修飾

關注三個問題:

  1. 如何例項化成員內部類的物件
		//建立Brain例項 靜態的成員內部類
		Person.Brain br=new Person.Brain();
		//建立Eye例項 非靜態的成員內部類
		Person person=new Person();
		Person.Eye eye=person.new Eye();
  1. 如何在成員內部類中區分呼叫外部類的結構

如果Person有內部類Brain,都定義了name屬性,且Brain中有個方法形參為name,則

name 形參

this.name Brain類中的

Person.name Person中的

  1. 開發中區域性內部類的使用

面試題:抽象類與介面異同

相同點:

  • 不能例項化
  • 都可以被繼承

不同點:

  • 抽象類有構造器,介面不能宣告構造器
  • 抽象類只能單繼承,介面可以多繼承