Java基礎系列之面向對象

在初遇章節我們就談到過Java是一門面向對象的語言,那么什么是面向對象呢?既然有面向對象語言,是否就有其他的語言?面向對象又能給我么帶來什么好處呢?接下來,我們將在這個章節探討下面向對象。

面向過程和面向對象


在目前的軟件開發領域有兩種主流的開發方法:結構化開發方法(面向過程)和面向對象開發方法。早期的編程語言C、Basic、Pascal等都是結構化編程語言,隨著時代的變遷,軟件的發展,人們發現了一種更好的可復用、可擴展和可維護的的方法,即面向對象,代表語言有C++,C#,Ruby,Java等。

  • 面向過程
    主張按功能來設計程序,特點是:自上而下,逐步求精,模塊化等。結構化程序設計的最小單元是函數,每個函數都負責完成一個功能。局限性有兩點:一,設計不夠直觀,與人類習慣思維不一致;二,適應性差,可擴展性不強。
  • 面向對象
    更優秀的程序設計思想,基本思想是使用類、對象、繼承、封裝、消息等基本概念進行程序設計。最小單位是類,由類可以生成系統中多個對象。

面向對象的基本特征


  • 封裝
    隱藏細節,通過公共方法暴露出該對象的功能。比如說一臺電腦,我們在不拆機的情況下看不到里面的主板,cpu,內存條,這些好比是私有方法,我們無法直接訪問,但是我們可以訪問它的鍵盤,開機鍵,顯示器,這些就是公共方法。
  • 繼承
    軟件復用的重要手段,子類繼承父類,可以直接復用父類的屬性和方法。
  • 多態
    子類對象直接賦給父類變量,運行的時候表現為子類的特性。

抽象也是面向對象的重要組成之一,但是不是基本特征。抽象是抽取我們當前目標所需要的東西,排除一些無關的信息。

Java面向對象特征


在初遇章節我們就談過Java的面向對象特征,我們這里再次談談Java面向對象特征。

  • 一切皆是對象
    除了8個基本數據類型,一切皆是對象。對象實現了數據和操作的結合,是Java的核心,具備唯一性,每個對象都有一個標識來引用,如果失去這個引用,那么這個對象將會變成垃圾,然后會被虛擬機回收掉。Java中不允許直接訪問對象,而是通過一個引用(也有一種稱呼為句柄)來操作對象。就如同設計一臺電視機,電視機上沒有任何按鈕,只能通過遙控來操作電視機。而這個遙控就是引用(句柄),電視機就是對象。
    如 Person p = new Person();


    image.png

    p就是一個引用變量,其實就是C語言中的指針,只是Java友好的將這個指針封裝起來了,不需要繁瑣的去操作它。p中存儲的是Person的地址,當訪問p引用變量的成員變量和方法,其實就是訪問Person的成員變量和方法。

  • 類和對象
    對象也稱為實例instance,對象的抽象化是類,類的具體化是對象。Java語言使用class來定義對象,通過成員變量來描述對象的數據,通過方法來描述對象的行為特征。類之間的關系一般有兩種:
    1. 一般->特殊關系(is a),Java中使用extends來表示這種特殊的關系,即繼承關系。
      發生在繼承關系常見的一個概念是重寫(Overrride),重寫必須符合規則式:兩同兩小一大。即,方法名,形參列表相同;返回值類型要比父類的返回值類型更小或者相等;子類拋出的異常必須比父類的異常更小或者相等(不能一代不如一代);子類的訪問權限必須比父類的相等或者更大。
      這里需要注意的是當父類的方法是private修飾時,子類是不能訪問的。
    2. 整體->部分關系(has a),組合關系,即Java中一個類里面保存了另一個類的引用來實現這種關系。

修飾符


  • private 私有的(類訪問權限)
  • default 默認(包訪問權限)
  • protected 子類訪問權限
  • public 公共訪問權限

this和super


面向對象離不開this和super,這里我們分析下這兩個關鍵字

  • this
    this關鍵字指向調用該方法的對象,一般會出現在構造器和方法中。我們知道一種特殊的方法static修飾的,就是靜態方法,調用靜態方法可以使用類對象,所以this無法指向調用該方法的對象,所以靜態方法里面不能使用this,同樣,靜態方法中不能使用非靜態成員變量。
  • super
    super是用來子類調用父類的方法或者構造方法的。和this一樣,super也不能應用在靜態方法中
    子類調用父類構造器過程是:
    1. 子類構造器執行體的第一行使用super顯式調用父類構造器,系統會根據super傳入的實例列表調用父類對應的構造器。
    2. 子類構造器執行體的第一行使用this顯式的調用本類的重載構造器,執行本類的另一個構造器時即會調用父類構造器。
    3. 子類構造器既沒有super,也沒有this,系統將會執行子類構造器之前,隱式的調用父類的無參構造器

final修飾符


final用來修飾類、變量、方法表示該類、變量、方法不可改變。

  • final修飾變量
    final修飾變量一旦獲得初始值后是不能改變的。如下圖,我們編譯器在編譯過程中就會報錯The final local variable a may already have been assigned
    image.png

    關于final修飾成員變量,必須顯式的初始化。
    1.普通成員變量,必須在初始化塊(代碼塊)、聲明時或者構造器中初始化。
    1. 靜態成員變量,必須在靜態代碼塊、聲明時初始化。
      其實final的不可改變也不是絕對的,這就是final修飾基本類型變量和引用類型變量的區別,修飾引用類型時,只要保證引用類型的地址不變,而引用的這個對象完全可以改變。
  • final方法
    final方法不能被重寫,如果父類不想讓子類繼承某個方法,可以定義為final類型。
  • final類
    final類不能有子類

聊聊Lambda表達式


Lambda表達式是Java8新增的一個重要功能,是大家期待已久的,它使得代碼更為的簡潔、直觀,接下來讓我們了解下Lambda表達式的功能。

  • 組成部分
    1. 形參列表。允許省略參數類型,如果是一個參數甚至可以省略圓括號
    2. 箭頭。(->)必須是英文的劃線號和大于號組成
    3. 代碼塊。 如果代碼塊只有一條語句,可以省略花括號。如果只有一條返回語句,return關鍵字也可以省略。
      比如說,我們可以創建一個線程類
Thread thread = new Thread((Runnable) ()->{
            System.out.println(Thread.currentThread().getName()+"-run--");
        });

這樣寫也是可以的

Thread thread = new Thread(()->System.out.println(Thread.currentThread().getName()+"-run--"));
  • 方法引用和構造器引用
@FunctionalInterface
    interface Converter{
        Integer converter(String from);
    }
Converter converter = from ->Integer.valueOf(from);

上面代碼其實就是對接口Converter的一個實現,然后把實現的地址賦給了引用變量converter。上面的代碼還可以簡寫成

Converter converter = Integer::valueOf;

調用converter.converter("5");也就是調用Integer.valueOf("5");
Lambda還有很多有意思的寫法,這就需要通過實踐中去探索了。

實戰


沒有實戰的概念就是耍流氓。

  • 一個比較坑的問題
public class StaticThreadDemo implements Runnable{
    public static Integer i = new Integer(0);
    @Override
    public void run() {
        while(true){
            synchronized (i) {
                if(i<100){
                    i++;
                    System.out.println("i="+i);
                }else{
                    break;
                }
            }
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(new StaticThreadDemo());
        Thread t2 = new Thread(new StaticThreadDemo());
        t1.start();
        t2.start();
    }
}

問題輸出的結果是啥?按順序1-100?重復輸出1-100?無序的1-100?
運行的結果是:無序的,有重復,有確實的打印1-100。
就是說,這是個線程不安全的程序。那么為什么會導致這種情況呢?
分析:
synchronized 鎖對象的問題。我們知道,靜態變量和類信息(區分類對象)都是存放在我們的方法區中(因此靜態變量屬于類本身而不屬于實例),我們可以認為是線程共享的,唯一的。那,我們應該要理解的是引用i對應的對象是否被偷換的問題,如果沒有變化,那么,i肯定是線程安全的。我們編譯下這段代碼。

public class StaticThreadDemo implements Runnable {
    public static Integer i = new Integer(0);

    public StaticThreadDemo() {
    }

    public void run() {
        while(true) {
            Integer var1 = i;
            synchronized(i) {
                if(i.intValue() >= 100) {
                    return;
                }
                Integer e = i;
                i = Integer.valueOf(i.intValue() + 1);
                System.out.println("i=" + i);
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new StaticThreadDemo());
        Thread t2 = new Thread(new StaticThreadDemo());
        t1.start();
        t2.start();
    }
}

我們發現:Integer要獲取它的數據需要通過intValue() 方法,那么intValue()方法干了件什么事呢?查看Integer對象源碼

private final int value;
  public int intValue() {
        return value;
    }

我們上面說過,對象的數據使用成員變量來描述,而這個成員變量是私有的,我們只能通過它的方法來獲取。
i++分解成了兩句

 Integer e = i;
 i = Integer.valueOf(i.intValue() + 1);

第一句我們比較好理解,就是用一個新的對象保存舊的數據,而第二句才是重點,我們先看下Interger的靜態方法valueOf

   public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

解釋一下這段代碼,就是當i的字段在-128和127之間的話,從IntegerCache緩存里面獲取,如果在區間之外的話,重新new一個對象,當然,緩存里面其實也是new Integer(i);所以說i的對象發生了改變了,因此,synchronized鎖不住對象了。
我們可以這樣理解這個流程,線程t1獲取鎖對象,進入run方法,執行i++后,鎖對象發生了改變,這個時候線程t1,t2一起爭取新的鎖對象,由于這一步和打印語句并行,所以存在線程安全問題。


image.png

這里提一下Integer內部類IntegerCache緩存對象問題,在Java5加入了自動裝箱和自動拆箱后(實現原理就是valueOf方法),如果int值在-128和127之間,Java不會new一個對象,而是直接從緩存里面獲取了,這就有了面試題Integer a =127;Integer b = 127;Integer c =128;Integer d = 128;
System.out.println(a==b); System.out.println(c==d);

尾聲

通過本章節,我們說到了面向對象的基本特性與面向過程的優勢所在,然后闡述了Java面向對象的特征,引出了引用數據類型。后面我們說到了一些修飾符,如訪問權限修飾符,關鍵字等。還提到了Java8新增的Lambda表達式的應用。總之,Java面向對象博大精深,不是一篇文章就能說得清楚的,如果要深入學習,我們還需要閱讀相關的書籍。在最后,我舉了一個多線程安全問題的案例,詳細分析了Integer對象在i++過程中的實際操作以及對象之間的變化,希望能幫到大家進一步了解面向對象思想。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容

  • 一、Java 簡介 Java是由Sun Microsystems公司于1995年5月推出的Java面向對象程序設計...
    子非魚_t_閱讀 4,235評論 1 44
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,726評論 18 399
  • 整理來自互聯網 1,JDK:Java Development Kit,java的開發和運行環境,java的開發工具...
    Ncompass閱讀 1,549評論 0 6
  • 幸福快樂的生活 ① 清晨醒來,我看見透過窗簾的一縷陽光,心里很溫暖,前幾天還被窗外嘰嘰喳喳叫喚的小鳥們從夢中吵醒,...
    風光美景888閱讀 870評論 5 5
  • 互聯網發展至今,改變了世界。我認為這是繼兩次工業革命以來,給世界帶來的第三次巨大改變。 而技術對人類的改變,往往以...
    WillYang01閱讀 450評論 0 1