面向物件(下)--static/final/程式碼塊/抽象/介面/內部類
目錄
1 關鍵字:static
2 理解main方法的語法
3 類的成員之四:程式碼塊
4關鍵字:final
5 抽象類與抽象方法
6 介面(interface)
7 類的成員之五:內部類
static
功能
-
含義:靜態的
-
可以用來修飾屬性、方法、程式碼塊、內部類
-
使用static修飾屬性:表示靜態變數(類變數),沒有static的為例項變數,如果建立了類的多個物件,多個物件共享同一個靜態變數,當通過某一個物件修改靜態變數時,會導致其他物件呼叫此靜態變數時是修改過的
靜態變數的其他說明:
- 靜態變數隨著類的載入而載入,早於物件的建立,和類一樣只會載入一次,在記憶體中存在一份
- 可以通過類.靜態變數的方式進行呼叫,而例項變數不能這樣呼叫
- 記憶體解析:
- 靜態方法:類似靜態變數,可以通過類之間呼叫,隨著類載入,只能呼叫靜態的方法或屬性,對於非靜態方法中,既可以呼叫非靜態方法或屬性,也可以呼叫靜態方法或屬性
- 注意點:
- 靜態的方法內,不能使用this關鍵字、super關鍵字
- 關於靜態屬性和靜態方法的使用,可以從生命週期的角度理解
- 開發中,如何確定一個屬性是否要宣告為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;
}
}
區分餓漢式和懶漢式
餓漢式:物件載入時間過長(缺點),是執行緒安全的(優點)
懶漢式:延遲物件的建立(優點),目前的寫法執行緒不安全,多執行緒內容時可以修改
使用場景
只生成一個例項,減少了系統性能開銷,當一個物件的產生需要比較多資源時,可以直接產生一個單例物件,永久駐留記憶體
- 網站計數器,為了保證同步
- 應用程式的日誌應用,因為日誌檔案一般一直處於開啟操作,便於追加
- 資料庫連線池,一個池子可以同時進行n個連線, 連線池固定一個
- 讀取配置檔案的類
- Application類
- windows工作管理員、回收站等
理解main方法的使用
- main()方法作為程式的入口
- main()也是一個普通的靜態方法
- 可以作為我們與控制檯互動的方式,之前是使用Scanner
類的成員四:程式碼塊
相當於對屬性賦值多了一種方式,實際上使用頻率不高
- 程式碼塊作用:用於初始化類、物件
- 程式碼塊如果有修飾,只能使用static
- 分類:靜態程式碼塊 非靜態程式碼塊
- 靜態程式碼塊:
- 內部可以有輸出語句
- 隨著類的載入而執行;
- 用於初始化類的資訊;
- 如果一個類中定義了多個靜態程式碼塊,則按照宣告的先後順序執行;
- 靜態程式碼塊的執行要優先於非靜態程式碼塊的執行
- 非靜態程式碼塊:
- 內部可以有輸出語句
- 隨著物件的建立(new)而執行
- 每建立一個物件就執行一次
- 作用是可以在建立物件時,對物件的屬性等進行初始化
- 如果一個類中定義了多個非靜態程式碼塊,則按照宣告先後順序執行
- 屬性賦值的執行順序
預設初始化--顯式初始化/程式碼塊中賦值--構造器中初始化--物件.屬性或物件.方法賦值
final關鍵字
- final可以修飾的結構:類、方法、變數
- final類:此類不能被其他類繼承,如String、System、StringBuffer
- final方法:不允許被重寫,比如Object中getClass
- final變數:此時的變數稱為是一個常量,不允許改變
- 允許的賦值位置有:顯示初始化,程式碼塊中初始化、構造器中初始化
- final區域性變數:尤其是使用final修飾形參時,表明此形參是常量,呼叫此方法時給該形參賦值,之後方法中只能使用不能重新賦值
- static final修飾屬性:全域性常量,介面中屬性全是全域性常量
- 用途:一般方法不常使用,屬性有時需要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關係,只是有相同的行為特徵。如大學生中學生都是學生,跨欄運動員籃球運動員都是運動員,他們都具有學習的技能,一方面他們已經有父類,另一方面他們與技能不滿足子父類關係,因此可以把技能定義為介面
介面的使用
-
介面使用interface來定義
-
java中,介面和類是並列的兩個結構
-
如何定義介面:定義介面中的成員
3.1 JDK7及以前:介面中只能定義全域性常量和抽象方法
全域性常量:
public static final
(即使省略這幾個詞依然是全域性常量)抽象方法:
public abstract
(即使省略這幾個詞依然是抽象方法)介面中不能定義構造器!!意味著介面不可以例項化
3.2 JDK8以後 除了全域性常量和抽象方法還可以定義靜態方法和預設方法
-
Java開發中,介面通過讓類去實現(Implements)的方法來使用
如果實現類重寫了介面中所有抽象方法,則此實現類可以例項化
如果沒有覆蓋所有抽象方法,則此實現類仍為抽象類
-
java類可以實現多個介面,打破了類的單繼承性的侷限性,多個介面用
implements A,B
即可 -
介面與介面間可以繼承,且可以多繼承
-
介面的具體使用體現的多型性,介面實際上可以看做一種規範
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");
}
}
內部類
一個類定義於另一個類的內部,稱為內部類,反之為外部類
- 內部類一般用在定義它的類或語句塊內,外部引用時必須給出完整的名稱
- 內部類分類:成員內部類(靜態、非靜態) 區域性內部類(方法內、程式碼塊內、構造器內)
- 成員內部類:可以呼叫外部類的結構;可以定義屬性、方法、構造器等;可以被final、abstract修飾
關注三個問題:
- 如何例項化成員內部類的物件
//建立Brain例項 靜態的成員內部類
Person.Brain br=new Person.Brain();
//建立Eye例項 非靜態的成員內部類
Person person=new Person();
Person.Eye eye=person.new Eye();
- 如何在成員內部類中區分呼叫外部類的結構
如果Person有內部類Brain,都定義了name屬性,且Brain中有個方法形參為name,則
name 形參
this.name Brain類中的
Person.name Person中的
- 開發中區域性內部類的使用
面試題:抽象類與介面異同
相同點:
- 不能例項化
- 都可以被繼承
不同點:
- 抽象類有構造器,介面不能宣告構造器
- 抽象類只能單繼承,介面可以多繼承