1. 程式人生 > 實用技巧 >java基礎---類和物件(4)

java基礎---類和物件(4)

一、 static關鍵字

使用static關鍵字修飾成員變量表示靜態的含義,此時成員變數由物件層級提升為類層級,整個類共享一份靜態成員變數,該成員變數隨著類的載入準備就緒,與是否建立物件無關

  • 使用static修飾屬性:靜態變數(或類變數)
    • 靜態變數隨著類的載入而載入,可以通過類名.靜態變數的方式進行呼叫
    • 靜態變數的載入遭遇物件的建立
    • 類只會載入一次,靜態變數在記憶體中只有一份,在方法區的靜態域中
  • 使用static關鍵字修飾類方法:靜態方法
    • 靜態方法中只能代用靜態方法的屬性或方法
    • 非靜態方法中,可以呼叫非靜態的方法和屬性,也可以呼叫靜態的方法和屬性
  • 特點:
    • Java類中, 可用static修飾屬性、 方法程式碼塊、 內部類,不能修飾構造器
    • 被static修飾的成員隨著類的載入而載入,優先於物件存在,被所有物件共享
    • 可以直接被類呼叫,通過類名.靜態成員變數或方法的方式
  • 注意事項:
    • 在非靜態成員方法中既能訪問非靜態成員,又能訪問靜態成員 (成員:成員變數+成員方法, 靜態成員被所有物件共享)  
    • 靜態成員方法中職能訪問靜態成員,不能訪問非靜態成員(成員:成員變數+成員方法, 因為此時可能還沒有建立物件)
    • 隸屬於類層級並被所有物件共享的才尅使用static關鍵字修飾
    • 在靜態的方法內,不能使用this關鍵字、super關鍵字
    • static修飾的方法不能被重寫
  • 記憶體解析

  

二、程式碼塊

程式碼塊用於初始化類和物件,只能用static修飾,分為靜態程式碼塊和非靜態程式碼塊

  • 靜態程式碼塊
    • 內部可以有輸出語句,隨著類的載入而執行,只執行一次,初始化類的資訊
    • 不可以對非靜態的屬性初始化,不可以呼叫非靜態的屬性和方法
    • 如果一個類中定義了多個靜態程式碼塊,按照宣告的先後順序執行
    • 靜態程式碼塊的執行優先於非靜態程式碼塊的執行
    • 靜態程式碼塊只能呼叫靜態的屬性和靜態犯法,不能呼叫非靜態的結構
  • 非靜態程式碼塊
    • 內部可以有輸出語句
    • 隨著物件的建立而執行
    • 每建立一個物件就會執行一次非靜態程式碼塊,可以在建立物件
    • 如果一個類中定義了多個非靜態程式碼塊,按照宣告的順序先後執行
    • 非靜態程式碼塊可以呼叫靜態的屬性和方法或者非靜態的屬性和方法
  • 對屬性可以賦值的位置:
    ①預設初始化-->②顯式初始化/⑤在程式碼塊中賦值(同級別下按先後順序執行

    )-->③構造器中初始化-->④有了物件以後,可以通過"物件.屬性"或"物件.方法"的方式,進行賦值  

package com.atguigu.java3;
class Root{
    static{
        System.out.println("Root的靜態初始化塊");
    }
    {
        System.out.println("Root的普通初始化塊");
    }
    public Root(){
        super();
        System.out.println("Root的無引數的構造器");
    }
}
class Mid extends Root{
    static{
        System.out.println("Mid的靜態初始化塊");
    }
    {
        System.out.println("Mid的普通初始化塊");
    }
    public Mid(){
        super();
        System.out.println("Mid的無引數的構造器");
    }
    public Mid(String msg){
        //通過this呼叫同一類中過載的構造器
        this();
        System.out.println("Mid的帶引數構造器,其引數值:"
            + msg);
    }
}
class Leaf extends Mid{
    static{
        System.out.println("Leaf的靜態初始化塊");
    }
    {
        System.out.println("Leaf的普通初始化塊");
    }    
    public Leaf(){
        //通過super呼叫父類中有一個字串引數的構造器
        super("mid");
        System.out.println("Leaf的構造器");
    }
}
public class LeafTest{
    public static void main(String[] args){
        new Leaf(); 
        System.out.println();
        new Leaf();
    }
}

//執行結果
/*
Root的靜態初始化塊
Mid的靜態初始化塊
Leaf的靜態初始化塊
Root的普通初始化塊
Root的無引數的構造器
Mid的普通初始化塊
Mid的無引數的構造器
Mid的帶引數構造器,其引數值: mid
Leaf的普通初始化塊
Leaf的構造器
*/

三、final關鍵字

final可以用於修飾類、方法和變數,意為最終的,不可變的

  • final 用來修飾一個類:此類不能被其他類所繼承。
  • final 用來修飾方法:表明此方法不可以被重寫
  • final 用來修飾變數:此時的"變數"就稱為是一個常量,可以考慮賦值的位置有:顯式初始化、程式碼塊中初始化、構造器中初始化
  • final修飾區域性變數,表明形參是一個常量,一旦賦值不能在進行重新賦值
  • static final 用來修飾屬性:全域性常量
public class FinalTest {

    final int WIDTH = 0;
    final int LEFT;
    final int RIGHT;
//    final int DOWN;

    {
        LEFT = 1;
    }

    public FinalTest(){
        RIGHT = 2;
    }

    public FinalTest(int n){
        RIGHT = n;
    }

    public void setDown(int down){
     //  this.DOWN = down;  //在方法體不可以對final屬性進行賦值操作
    }


    public void doWidth(){
   //     width = 20;//在方法體不可以對final屬性進行賦值操作
    }


    public void show(){
        final int NUM = 10;//常量
     //  NUM += 20;  //final區域性變數一旦初始化不可以在被複制
    }

    public void show(final int num){
              //  num = 20;//final 區域性變數一旦被實參傳入,就已經賦值,不能重新賦值,編譯不通過
        System.out.println(num);
    }


    public static void main(String[] args) {

        int num = 10;

        num = num + 5;  //區域性變數可以重複賦值

        FinalTest test = new FinalTest();
//        test.setDown(3);

        test.show(10);
    }
}


final class FinalA{

}

//class B extends FinalA{
//    
//}

//class C extends String{
//    
//}

class AA{
    public final void show(){

    }
}

class BB extends AA {
    /*public void show(){        //final方法不可以被重寫
}*/     
}

final class Root{}
// class  sub extends  Root{}  //  final 類不可以被繼承

四、abstract關鍵字

abstract用於修飾抽象的類或方法,抽象類使用extends實現

  • 抽象類:指不能具體例項化的類並且使用abstract關鍵字修飾,也就是不能建立物件
    • 抽象類中一定有構造器,便於子類例項化時呼叫,但是抽象類不能呼叫自身構造器例項化
    • 多型的一種表現形式:抽象類的子類例項化形成抽象類
    • 抽象類中可以有成員變數、構造方法、成員方法
    • 抽象類中可以沒有抽象方法,也可以有抽象方法
    • 當一個類繼承抽象類後必須重寫抽象方法,否則該類也變成抽象類,也就是抽象類對子類具有強制性和規範性,因此叫做模板設計模式
  • 抽象方法:抽象方法用abstract修飾方法,沒有方法體
    • 包含抽象方法的一定是抽象類,抽象類可以沒有抽象方法
    • 若子類重寫了父類的所有抽象方法後,子類可以例項化
    • 若子類沒有全部重寫父類中的所有抽象方法,該子類也是一個抽象類,需要適用abstract修飾
  • abstract不能用來修飾私有方法、靜態方法、final的方法、final的類 

五、介面

介面使用interface定義,使用implements實現

  • JDK7以前,接口裡只能定義全域性變數和抽象方法,(public static final)+ 常量;public abstract+ 方法
  • JDK8以後,介面可定義靜態方法和預設方法

  

interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable,
Bounceable {
Ball ball = new Ball("PingPang");
}
class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name = name;
}
public void play() {
ball = new Ball("Football");
System.out.println(ball.getName());
}
}
  • 介面不可以定義構造器,沒有預設構造器,不能例項化
  • 如果實現類覆蓋了介面中的所有抽象方法,該實現類可以被例項化,否則該實現類是一個抽象類
  • 介面和介面之間可以多繼承,實現類和介面之間可以多實現
  • 介面主要用於代理模式,為其他物件提供一種代理以控制對這個物件的訪問。
  • 介面可以用於工廠模式

若一個介面中定義了一個預設方法,而另外一個介面中也定義了一個同名同參數的方法,在實現類同時實現了這倆個介面時會出現介面衝突

class Man implements Filial, Spoony {
    @Override
    public void help() {
        System.out.println("我該怎麼辦呢?");
        Filial.super.help();
        Spoony.super.help();
    }
}
interface Filial {// 孝順的
    default void help() {
        System.out.println("老媽,我來救你了");
    }
}
interface Spoony {// 痴情的
    default void help() {
        System.out.println("媳婦,別怕,我來了");
    }
}

若一個介面中定義了一個預設方法,而父類中也定義了一個同名同參數的非抽象方法,由於類優先原則,不會出現衝突問題,介面中的同名同參數預設方法會被忽略

七、內部類

一個類的定義位於另一個類的內部稱為內部類 ,Inner class一般用在定義它的類或語句塊之內,在外部引用它時必須給出完鄭的名稱,且內部類不能與他所在的外部類同名

  • 類中的內容:成員變數、成員方法、構造方法、靜態成員、構造塊和靜態程式碼塊、內部類。
  • 當一個類存在的價值僅僅是為某一個類單獨服務時,那麼就可以將這個類定義為所服務類中的內部類,這樣可以隱藏該類的實現細節並且可以方便的訪問外部類的私有成員而不再需要提供公有的getset方法
  • 分類:

    • 普通內部類 - 直接將一個類的定義放在另外一個類的類體中。 

      • 普通內部類和普通類一樣可以定義成員變數、成員方法以及構造方法等。

      • 普通內部類和普通類一樣可以使用final或者abstract關鍵字修飾。

      • 普通內部類還可以使用privateprotected關鍵字進行修飾。

      • 普通內部類需要使用外部類物件來建立物件

      • 如果內部類訪問外部類中與本類內部同名的成員變數或方法時,需要使用this關鍵字
訪問修飾符 class 外部類的類名 {
訪問修飾符 class 內部類的類名 {
內部類的類體;
}
    • 靜態內部類 - 使用static關鍵字修飾的內部類,隸屬於類層級 

      • 靜態內部類不能直接訪問外部類的非靜態成員。靜態內部類可以直接建立物件。

      • 如果靜態內部類訪問外部類中與本類內同名的成員變數或方法時,需要使用類名.的方式訪問。

訪問修飾符 class 外部類的類名 {
訪問修飾符 static class 內部類的類名 {
內部類的類體;
}
}
    • 區域性內部類 - 直接將一個類的定義放在方法體的內部時

      • 區域性內部類只能在該方法的內部可以使用。

      • 區域性內部類可以在方法體內部直接建立物件。

      • 區域性內部類不能使用訪問控制符和static關鍵字修飾符。

      • 區域性內部類可以使用外部方法的區域性變數,但是必須是final的,因為區域性內部類和區域性變數的宣告週期不同所致     

訪問修飾符 class 外部類的類名 {
訪問修飾符 返回值型別 成員方法名(形參列表) {
class 內部類的類名 {
內部類的類體;
}
}
}
    • 匿名內部類 - 就是指沒有名字的內部類
介面/父類型別 引用變數名 = new 介面/父類型別() { 方法的重寫 };