Java幾個重要的關鍵字詳析

1.extends

  • 用於類繼承類,用法:class+子類名+extends+父類名+{}
class Animal{}//父類
class cat extends Animal{}//子類用extends實現繼承 

註意:一個類隻能用extends關鍵字聲明繼承一個父類

  • 用於接口繼承接口,用法:interface+接口名+extends+接口名+{}
interface Clippers {}
interface Warriors {}
interface Lakers extends Clippers,Warriors {}//接口類用extends關鍵字繼承其他接口(可多個)

註意:

  • 接口不能用extends聲明繼承別的
  • 接口隻能用extends聲明繼承別的接口,且可以繼承多個接口
  • 當一個類用implements實現瞭一個接口時,不僅要實現該接口的方法,也要實現該接口繼承的接口的方法

2.implements

  • 用於聲明一個類實現瞭一個接口類,用法:class+類名+implements+接口名+{}
class Nets implements Clippers,Warriors{}//用implements關鍵字聲明實現瞭兩個接口類

註意:

  • 一個普通類可以implements關鍵字聲明實現多個接口,但必須實現所有接口中的所有方法
  • 抽象類實現接口,可以不用實現接口的方法(因為抽象類中可以有抽象方法)
  • 意義:可以用implements關鍵字聲明實現多個接口來實現類似多繼承

3.final

使用方法:

  • 修飾,使該類不能被繼承
  • 修飾方法,使該方法不能被子類重寫 (仍可以被繼承調用
  • 修飾屬性,使該屬性的值不能被修改(使為常量
  • 修飾局部變量,使該變量不能被修改(局部常量

使用細節:

final修飾的屬性在定義時必須賦初值,且不能修改,可以在以下位置賦初值

  • 定義時(顯示初始化)
  • 在構造器中
  • 在代碼塊中

static final:全局常量

  • 如果final修飾的屬性是靜態(static)的,則不能在構造器中賦初值,原因:靜態屬性要求在類加載時就有初值,而構造器在創建對象時才被調用,所以可能導致調用靜態屬性時沒有創建對象而沒有給靜態屬性賦值
  • final不能修飾構造方法,沒有意義
  • finalstatic同時修飾的屬性在調用時不會導致類的加載,效率更高

4.native

基本介紹:

native用來修飾方法,被修飾的方法即成為瞭一個Java調用但非Java代碼實現的接口(本地方法) ,該方法在外部可以用任何語言去實現

"A native method is a java method whose implementation is provided by non-java code."

使用方法:

native修飾方法的位置必須在方法返回類型之前,和方法訪問修飾符位置沒有要求,如:public native int hashCode();

native細節:

  • native方法沒有方法體,也沒有{}
  • native修飾後的方法不能用abstract修飾,因為abstract指明該方法無實現體,而native方法是有實現體的,隻是用非Java代碼實現的
  • native方法的返回類型可以是任意類型
  • 如果一個有native方法的類被繼承子類會繼承這個native方法,並且可以用java語言重寫

使用JNI(Java Native Interface) 與其他語言交互

JNIJava平臺的一部分,它允許Java代碼和其他語言寫的代碼進行交互。

使用步驟:

  • 編寫帶有native方法的java類,生成.java文件
  • 使用javac命令編譯生成.class文件
  • 使用javah -jni 類名 生成.h文件
  • 使用C/C++(或者其他編程語言)實現native方法,創建.cpp(或其他)文件
  • C/C++編寫的文件創建動態鏈接庫(生成DLL文件)
  • native方法中使用System.loadLibrary()方法加載動態庫,將DLL文件名作為參數傳入,這時候再運行.java程序即可實現對本地方法的調用

詳細步驟參考

native意義:

Java無法直接訪問到操作系統底層(如系統硬件),但通過使用native關鍵字修飾方法可以借用其他的語言來擴展Java程序的功能,提高程序的效率

5.static

修飾變量,成為靜態變量或者類變量

  • 使用方法:訪問修飾符+``static``+數據類型+變量名

註意事項:

  • 靜態變量會被類的所有對象實例共享,並且在類加載的時候就會初始化。
  • 靜態變量的訪問方法(遵守相關訪問權限):類名.靜態變量名 或者 對象名.靜態變量名

修飾方法,成為靜態方法或者類方法

  • 使用方法:訪問修飾符+``static``+返回數據類型+方法名+{}

註意事項:

  • 調用方法(遵守相關訪問權限):類名.靜態方法名 或者 對象名.靜態方法名
  • 靜態方法普通方法都是隨著類加載而加載,將結構信息存儲在方法區
  • 靜態方法中不允許使用thissuper關鍵字
  • 靜態方法中隻能訪問靜態變量靜態方法
  • 普通方法可以訪問靜態成員和普通成員
  • 修飾代碼塊,成為靜態代碼塊

靜態代碼塊會在類加載時被加載,優先級和靜態屬性一樣,有多個靜態代碼塊和靜態屬性時,初始化順序按定義順序執行

好處:static關鍵字的使用,將類中的一些成員修飾成靜態的,這樣我們不需要創建該類的對象就可以調用該成員,大大提高瞭編程效率

6.transient

基本介紹:

transient用於修飾實現瞭Serilizable接口的類中的成員變量,在該類的實例對象進行序列化處理時transient修飾的成員變量不會進行序列化

使用例子:

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectOutputStream;
import java.io.Serializable;
public class outStream {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\Cat.txt";
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
        oos.writeObject(new Cat("小花貓", 3));
        oos.close();
    }
}
class Cat implements Serializable {
    private String name;
    private int age; //沒有用transient修飾
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Car{" +

                "name='" + name + ''' +

                ", age=" + age +

                '}';
    }
}
public class inStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String filePath = "d:\Cat.txt";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        System.out.println(ois.readObject());
        ois.close();
    }
}

可以在Cat.txt文件內看到兩個成員變量都能被序列化,並且能被反序列化讀出信息。

當小花貓覺得自己的年齡是隱私不想被讀出時,transient修飾成員變量age:

......
private String name;
private transient int age; //使用transient修飾
......

這時在Cat.txt文件中可以看到隻有name一個成員變量被序列化,反序列化後的成員變量age讀出的是int類型的默認值,說明對於transient修飾的成員變量,在類的實例對象序列化的過程中會被忽略

transient細節

  • transient修飾的成員變量可以理解為:不會參與進行對象的序列化和反序列化過程,生存周期僅存於調用者的內存不會寫進磁盤裡進行持久化
  • static修飾的成員變量(靜態變量)也是不可序列化的,不論被transient修飾與否

因為序列化是保存的實例對象的狀態,而靜態變量保存的是類的狀態

  • transient關鍵字隻能修飾變量,不能修飾方法和類
  • transient關鍵字不能修飾局部變量
  • transient關鍵字修飾的是自定義類的變量,則該類需要實現Serilizable接口

註意:

實現Serilizable接口的類的實例對象是自動進行序列化的,如果序列化對象的類實現的是Externalizable接口,則序列化不會自動進行,需要實現接口內的方法指定要序列化的變量,這時與有無Transient修飾無關

7.synchronized

基本介紹:

關鍵字synchronized可以保證在同一時刻隻有一個線程可以執行被synchronized修飾的方法或代碼塊

線程同步

程序中多個線程都要使用同一個方法,而這個方法用synchronized進行瞭修飾,在多個線程調用這個方法時必須遵循同步機制

線程同步機制

當一個線程使用synchronized修飾的方法時,其他線程想使用這個方法時就必須等待,直到這個線程使用完synchronized方法

synchronized使用方法:

  • 普通同步方法:public synchronized void m () {}
public class syn implements Runnable {
    static int i = 0;
    public static void main(String[] args) throws InterruptedException {
        syn test = new syn();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
    }
    public synchronized void increase() {//被synchronized修飾的同步方法
        System.out.println(Thread.currentThread().getName() + "調用:" + i++);

    }
    @Override
    public void run() {
        for (int j = 0; j < 100; j++) {
            increase();
        }
    }
}

兩個線程同時調用一個對象的一個同步方法,由於一個對象隻有一把鎖,所以隻有一個線程能夠獲得該對象的鎖,另一個線程無法獲得,就不能調用該對象的synchronized方法,需要等對象被釋放後才能調用

從運行結果中可以證明線程1搶到瞭鎖,線程0必須等待線程1執行完畢,否則不能訪問該同步方法。

  • 靜態同步方法:public static synchronized void m () {}
public class syn implements Runnable {
    static int i = 0;
    public static void main(String[] args) throws InterruptedException {
        syn test = new syn();
        syn test1 = new syn();
        Thread t1 = new Thread(test);//傳入實例對象test
        Thread t2 = new Thread(test1);//傳入實例對象test1
        t1.start();
        t2.start();
    }
    public static synchronized void increase() {//同步靜態方法
        System.out.println(Thread.currentThread().getName() + "調用:" + i++);
    }
    @Override
    public void run() {
        for (int j = 0; j < 100; j++) {
            increase();
        }
    }
}

雖然兩個線程實例化瞭兩個不同的對象,但是synchronized修飾的是靜態方法,兩個線程仍然發生瞭互斥,因為靜態方法是依附與類的而不是對象,線程1先搶到瞭類的鎖,而線程0必須等待線程1執行完畢釋放才能調用同步方法

  • 同步代碼塊:synchronized(object) {}
public class syn implements Runnable {
    static Object object = new Object();//共享對象
    public static void main(String[] args) throws InterruptedException {
        syn test = new syn();
        syn test1 = new syn();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test1);
        t1.start();
        t2.start();

    }
    @Override
    public void run() {
        synchronized (object) {//代碼塊用靜態成員變量上鎖
            for (int j = 0; j < 100; j++) {
                System.out.println(Thread.currentThread().getName() + "調用第" + j + "次");
            }
        }
    }
}

同步代碼塊用兩個實例變量共享的靜態成員object對象來上鎖,雖然是兩個線程實例化兩個不同的對象,但是對整個syn類來說隻有一個共享的object對象,所以隻有一把鎖,每當有線程來訪問代碼塊時需持有鎖,對象鎖被其他線程持有時需等待。線程1需要等線程0執行完畢才能訪問同步代碼塊

同步的局限性:

由於同步的方法或代碼塊隻能同一時間讓一個線程訪問,所以會導致程序的執行效率降低

盡可能synchronized修飾的范圍最小化,來減少互斥對程序執行帶來的影響

8.volatile

基本介紹:

volatile用於修飾變量,用volatile修飾的變量的值被某個線程修改時,會強制將修改的值立即寫入主存中,主存中的值更新會使得緩存中的該變量的值失效,對比與非volatile變量,可能會被其他線程讀取到更新前的值。

使用方法:

//現在有線程1和線程2同時執行下列代碼
int i = 0;
i = i + 1;

執行完畢後預想的結果是 i = 2;但是可能存在這樣一種情況:兩個線程先同時把i的值讀取到自己的工作內存中,然後再分別執行 i = i + 1 的操作,再將結果寫入主存,這樣兩個線程寫入的都是 i = 1,最終 i 的結果是 1 ,而不是 2

但如果 i 是 volatile 修飾的變量就會不一樣瞭,在一個線程修改 i的值後,會立即強制在主存中更新 i 的值,這樣會導致另一個線程的工作內存中 i 的緩存值無效,所以另一個線程再次從主存中讀取新的 i 的值,這樣保證瞭i的值是最新並正確的

並發編程的三大概念:

  • 原子性:執行一個操作時,要麼全部步驟執行完畢且不被中斷,要麼就不執行
x = 100;//是原子性操作
y = x;//不是原子性操作,可分解為:1.先讀取x的值    2.將x的值寫入主存
x ++;//不是原子性操作,可分解為:1.讀取x的值    2.進行加一操作    3.寫入主存
  • 可見性:多個線程對同一個變量進行操作時,一個線程修改瞭變量的值,其他線程能立即看到修改的值
  • 有序性:程序執行的順序按照代碼的先後順序執行

volatile的意義

  • 保證瞭不同線程對變量進行修改時的可見性:因為對於volatile變量來說,被修改後新值對其他線程來說是立即可見的
  • 保證瞭有序性volatile禁止瞭指令重排,它能保證在對volatile修飾的變量進行操作時,之前的代碼語句已經全部被執行,並且後面的語句都未執行,但是對其他語句的順序是不做保證的

註意: volatile不能保證原子性,因為不能保證對變量的操作是原子性操作

9.this

  • 在方法中修飾屬性,this理解為當前對象,用來區別成員方法和形參,通常省略
  • 修飾方法,this理解為當前對象,通常省略;不能在靜態方法中使用
  • 調用構造器,在構造器中使用this(形參列表)顯式調用指定的其他構造器
    • 必須在首行調用其他構造器
    • 一個構造器中不能調用多個其他構造器
    • 不能在構造器中調用遞歸調用,不能成環調用

10.super

super可以理解為:父類的

  • 修飾屬性:去父類中找對應屬性,用來區分子父類重名的屬性
  • 修飾方法:調用重寫之前的方法
  • 調用構造器:使用super(形參列表)指定調用父類構造器
    • super(形參列表)必須放在構造器的首行
    • super(形參列表)this(形參列表)隻能二選一
    • 在構造器首行如果沒有顯式聲明super(形參列表)this(形參列表)則默認調用父類的空參構造器super()(如果此時父類中沒有空參構造器就會報錯)
  • 不能在靜態方法中使用

當一個方法和屬性被static屬性修飾時,這些方法和屬性是優先於對象加載進入內存的,是隨著類的加載而加載的;this是當前對象的引用,super是指父類的引用,當靜態方法加載進內存進棧時,如果在靜態方法中有this和super關鍵字時,this和super也被加載到瞭內存,但是這個時候並沒有對象的引用,this和super沒有初始化,所有編譯會報錯。

10.1.子類對象實例化的過程

11.訪問修飾符

public修飾類:

  • 一個類中最多隻能有一個public類,且文件名要和public類一致
  • 如果沒有public類,文件名可以任意

到此這篇關於Java幾個重要的關鍵字詳析的文章就介紹到這瞭,更多相關Java關鍵字內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: