java編程思想-一切都是對象

1.一切都是對象  

     儘管Java是基於C++的,但是相比之下,Java 是一種更 純粹 的面向對象程序設計語言。

     C++和 Java 都是混合/雜合型語言。但是, Java 的設計者認爲這種雜合型並不像在C++中那麼重要。雜合型語言允許多種編程風格,C++之所以稱爲一種雜合型語言主要是因爲它支持與C語言的向後兼容。因爲C++是C的一個超集,所以勢必包括許多C語言不具備的特徵,這些特徵使C++在某些方面顯得過於複雜。

      Java 語言假設我們只進行面向對象的程序設計。也就是說,在開始用Java進行設計之前,必須將思想轉換到面向對象的世界中來。這個入門基本功,可以使你具備這樣一種編程語言的編程能力,這種語言學習起來更簡單,也比許多其他OOP語言更易用。

 

2.用引用操控對象

       直接操縱內存中元素的方式,在Java中的到了簡化。一切都被視爲對象,因此可採用單一固定的語法。儘管一切都看作對象,但操縱的標識符實際上是對象的一個 引用( reference ) ,可以將這一情形想象成用 遙控器(引用) 來操縱電視機(對象)。只要握住這個遙控器,就能保持與電視機的連接。當有人想改變頻道或者減少音量時,實際操縱的是遙控器(引用),再由遙控器來調控電視機(對象)如果想在房間內四處走走,同時仍能調控電視機,那麼只需攜帶遙控器(引用)而不是電視機(對象)。  

    此外,即使沒有電視機,遙控器亦可獨立存在,也就是說,你擁有一個引用,並不需要有一個對象與它關聯。因此,如果想操縱一個詞或者句子,則可以創建一個 String 引用:如下

String str;

   這裏所創建的只是引用,並不是對象。如果此時向 str 發送一個消息,就會返回一個運行時錯誤。 這是因爲此時 str 實際上沒有與任何事物相關聯。因此,一種安全的做法是 :創建一個引用的同時進行初始化:如下

String str="asdf";

這裏用到了Java語言的一個特性:字符串可以用帶引號的文本初始化。 通常,必須對對象採用一種更通用的初始化方法。

 

3.必須由你創建所有對象

      一旦創建了一個引用,就希望它能與一個新的對象相關聯。通常用 new 操作符來實現這一目的。 new 關鍵字的意思就是 "給我 一個新對象" ,所以前面的例子可以寫成如下:

String str= new String("asdf");

它不僅表示"給我一個新的字符串",而且通過提供一個初始字符串,給出了怎樣產生這個 String 信息。

當然,除了String 類型,Java 還提供大量過剩的現成類型。

 

3.1.存儲到什麼地方

  程序運行時,對象時怎麼進行放置安排的呢?特別是內存是怎樣分配的呢?對這些方面瞭解會對你有很大的幫助。有五個不同的地方可以存儲數據

1),寄存器。 這是最快的存儲區 ,因爲它位於不同於其他存儲區的地方__處理器內部。但是寄存器的數量及其有限,所以寄存器根據需求進行分配。你不能直接控制,也不能在程序中感受到寄存器存在的任何跡象(另一方面,C和C++允許您向編譯器建議寄存器的分配方式)

2),堆棧。位於通用RAM(隨機訪問存儲器)中,但通過 堆棧指針 可以從處理器哪裏獲得直接支持。堆棧指針若向下移動,則分配新的內存,若向上移動,則釋放那些內存。這是一種快速有效的分配存儲方法,僅次於寄存器。創建程序時,Java系統必須知道存儲在堆棧內所有項的準確生命週期,以便上下移動堆棧指針。這一約束限制了程序的靈活性,所以雖然某些Java數據存儲於堆棧中__特別是對象引用,但是Java對象並不存儲於其中。

3),。一種通用的內存池(也位於RAM區),用於存放 Java 對象。堆不同於堆棧的好處是:編譯器不需要知道存儲的數據在堆裏存活多長時間。因此,在堆裏分配存儲有很大的靈活性。當需要一個對象時,只需要 new 寫一行簡單的代碼,當執行這行代碼時,會自動在堆裏面進行存儲分配。當然,爲這種靈活性必須要付出相應的代碼,用堆進行存儲分配和清理可能比堆棧進行儲存分配需要更多的時間( 如果確實可以在Java中像在C++中一樣在棧中創建對象)

4),常量存儲。常量值通常直接存放在程序代碼內部,這樣做是安全的,因爲它們永遠不會被改變。有時,在嵌入式系統中,常量本身會和其他部分分隔離開,所以在這種情況下,可以選擇將其存放在ROM(只讀存儲器)中。

5),非RAM存儲。如果數據完全存儲於程序之外,那麼它可以不受程序的任何控制,在程序沒有運行時也可以存在。其中倆個基本的例子是流對象持久化對象。在流對象中,對象轉化成字節流,通常被髮送給另一臺機器。在持久化對象中,對象被存放於磁盤上,因此,即使程序終止,它們仍可以保持自己的狀態。這種存儲方式的技巧在於:把對象轉化成可以存放在其他媒介上的事物,在需要時,可恢復成常規的,基於RAM的對象。 Java 提供了對輕量級持久化的支持,而諸如JDBC 和 Hibernate 這樣的機制提供了更加複雜的對在數據庫中存儲和讀取對象信息的支持。

 

3.2.特例:基本類型

      在程序設計中經常使用一系列類型,他們需要特殊對待。可以把他們想象成基本類型。之所以特殊對待,是因爲 new 將對象存儲在 堆 裏面,故用new 創建一個對象__特別是小的,簡單的變量,往往不是很有效。因此,對於這些特殊類型,Java 和 C++採用了相同的方法。也就是說,不用new 來創建變量,而是創建一個並非引用的 自動 變量。這個變量直接存儲值,並置於堆棧中,因此更加高效。

    Java要確定每種基本類型所佔存儲空間大小。它們的大小並不像其他大多數語言那樣隨機器硬件架構的變化而變化。這種所佔存儲空間大小的不變性是Java 程序比用其他大多數語言編寫的程序更具可移植性的原因之一。

基本類型 大小 最小值 最大值 包裝器類型
boolean   __ __ __ Boolean
char 16-bit Unicode 0 Unicode 2^16-1 Character
byte 8-bits -128 +128 Byte
short 16bites -2^15 +2^15-1

Short

int 32bits -2^31 +2^31-1 Integer
long 64bits -2^63 +2^63-1 Long
float 32bits 1.4E-45 3.4028235E38 Float
double 64bits 4.9E-324 1.7976931348623157E308 Double
void __ __ __ Void
  • 所有的數值類型都有正負號,所以不要去尋找無符號的數值類型。
  • boolean 類型所佔存儲空間大下沒有明確指定,僅定義爲能夠取字面值 true 和 false。
  • 基本類型具有包裝器類,使得可以在堆中創建一個非基本對象,用來表示對應的基本類型。例如
        char c='c';
        Character character1=new Character(c);
        //也可以這樣寫
        Character character2=new Character('y');

Java SE5自動包裝功能將自動地將基本類型轉換爲包裝器類型:

      Character character='x';
      //可以進行反向轉換
       char c=character;
       System.out.println(c);

 

3.2.1.高精度數字

       Java 提供了倆個用於高精度計算的類: BigInteger BigDecimal 。雖然它們大體上屬於 包裝器類 的範疇,但二者都沒有對應的基本類型。

        不過,這倆個類包含的方法,提供的操作與對基本類型所能執行的操作相似。也就是說,能作用於 int 或 float 的操作,也同樣能作用於BigInteger 或者 BigDecimal 。只不過必須以方法調用方式取代運行符方式來實現。由於這麼做複雜了許多,所以運算速度會比較慢。在這裏,我們一速度換取了精度。

BigInteger 支持任何精度的整數。也就是說,在運算中,可以準確的表示任何大小的整數值,而不會丟失任何信息。

BigDecimal 支持任何精度的定點數,例如,可以用它進行精確的貨幣計算。

 

3.3 Java中的數組

      幾乎所有的程序設計語言都支持數組。在C和C++中使用數組是很危險的,因爲C和C++中的數組就是內存塊。如果一個程序要訪問其自身內存塊之外的數組,或數組初始化前使用內存(程序中常見的錯誤),都會產生難以預料的後果。

      Java的只要目標之一是安全性,所以許多在C和C++裏困擾程序員的問題在Java裏就不會出現。Java確保數組會被初始化,而且不能在它的範圍之外被訪問。這種範圍檢查,是以每個數組少量的內存開銷及運行時的下標檢查爲代價的。但由此換來的是安全性和效率的提高,因此付出的代價是值得的(並且Java有時可以優化這些操作)。

      當創建一個數組對象時,實際上就是創建了一個引用數組,並且每個引用都會自動被初始化爲一個特定值,該值擁有自己的關鍵字 null 。一旦Java 看到null ,就知道這個引用還沒指向某個對象。在使用任何引用前,必須爲其指定一個對象,如果試圖使用一個還是null的引用,在運行時報錯,因此,常見的數組錯誤在Java中就可以避免。

       還可以創建用來存放基本數據類型的數組。同樣,編譯器也能確保這種數組的初始化,因爲它會將這種數組所佔的內存全部置零。

 

4.永遠不需要銷燬對象

      大多數程序設計語言中,變量生命週期的概念,佔據了程序設計工作非常重要的部分,變量需要存活多長時間?如果想要銷燬對象,那麼時刻進行呢?變量生命週期混亂往往會導致大量的程序bug,本節將介紹Java是怎樣替代我們完成所有的清理工作,從而大大地簡化這個問題的。

4.1.作用域

  • 大多數過程型語言都有作用域(scope)的概念。作用域決定了再其內定義的變量名的可見性和生命週期。 在C , C++和Java中作用域由 花括號({}) 的位置決定。

4.2.對象的作用域

  • Java 對象不具備和基本類型一樣的生命週期。當用new 創建一個Java 對象時,它可以存活於作用域之外。例如
   {
        String s=new String("a String");
    }//End of scope
  1. 引用 s 在作用域終點就消失了。然而, s指向的 String 對象仍繼續佔據內存空間。在這一小段代碼中,我們無法在這個作用域之後訪問這個對象,因爲對它唯一引用已超出了作用域的範圍。
  2. 事實證明,由 new 創建的對象,只要你需要,就會一直保留下去。這樣,許多C++編程問題在Java中就完全消失了。在C++中,你不僅需要確保對象的保留時間與你需要這些對象的時間一樣長,而且還必須在你使用完它們之後,將其銷燬。
  3. 這樣便帶來一個有趣的問題。如果Java讓對象繼續存在,那麼靠什麼才能防止這些對象填滿內存空間,進而阻塞你的程序呢?這正是C++裏面可能發生的問題。這也是Java神器之所在。Java 有一個垃圾回收器,用來監視用new 創建的所有對象,並辨別哪些不會被引用的對象。隨後,釋放這些對象的內存空間,以便供其他新的對象使用。也就是說,你根本不需要擔心內存回收的問題。你只需要創建對象,一旦不再需要,它們就會自行消息。這樣做消除了這類編程的問題(即 內存泄漏) ,這是由程序員忘記釋放內存而產生的問題。

4.3.創建新的數據類型:類

  • 大多數面向對象的程序設計語言習慣用 關鍵字 class 來表示,如下
class HelloWord{ /** Class body goes here*/}

你可以使用 new 來創建這種類型的對象 如下

HelloWord helloWord=new HelloWord();

4.4.字段和方法

  • 一旦定義了一個類(Java中你所做的全部工作就是定義類,產生哪些類的對象,以及發送消息給這些對象),就可以在類中設置倆種類型的元素:字段(有時被稱作數據成員) 和 方法(有時被稱作成員函數)。字段可以是任何類型的對象,可以通過其引用與其進行通信,也可以是基本類型中的一種。如果字段是對某個對象的引用,那麼必須初始化該引用,以便使其與一個實際的對象相關聯。
  • 每個對象都有用來存儲其字段得空間,普通字段不能再對象間共享。下面是一個具有某些字段得類如下
public class DataOnly {
    int i;
    double d;
    boolean b;
}
  1. 儘管這個類除了存儲數據之外什麼也不做,但是仍舊可以像下面這樣創建它的一個對象。
DataOnly dataOnly = new DataOnly();
  • 可以給字段賦值,但首先必須知道如何引用一個對象的成員。具體的實現爲: 在對象引用的名稱之後緊接着一個句點,然後再接着是對象內部的成員名稱,如下:
        DataOnly dataOnly =new DataOnly();
        dataOnly.i=100;
        dataOnly.b=true;
        dataOnly.d=0.2d;
  • DataOnly 類除了保存數據外沒有別的用處,因爲它沒有任何成員方法。如果你想了解成員方法的運行機制,就得先了解參數和返回值得概念。

基本成員默認值

  • 若類的某個成員是基本數據類型,即使沒有進行初始化,Java也會確保它獲得一個默認值,如下圖
基本數據類型 默認值
boolean false
char

'\uoooo' (null)

byte 0
short 0
long 0L
int 0
float 0.0f
double 0.0d
  • 當變量作爲類的成員使用時,Java才確保給定其默認值,一確保那些是基本數據類型的成員變量得到初始化(C++沒有此功能),防止產生程序錯誤。但是,這些初始化對你的程序來說,可能不是正確的,甚至是不合法的。所以你最好明確得對變量進行初始化。
  • 然而上述確保初始化的方法並不適用於 局部 變量(即並非某個類的字段)。如下
    public void setId(){
        int x;
        System.out.println(x);
    }
  1. 那麼變量 x 得到的可能是任意值(與C和C++中一樣),而不會被自動初始化爲零。所以在使用 x前,應先對其賦一個適當的值。如果忘記了這麼做,Java就會在編譯時返回一個錯誤,告訴你此時變量沒有初始化,這正是Java優於C++的地方。(許多C++編譯器會對未初始化變量給予警告,而Java則視爲是錯誤)。

 

5.方法,參數和返回值

       許多程序設計語言(像C和C++)用函數這個術語來描述命名子程序,而在Java裏卻常用方法這個術語來表示 "做某些事情的方式"。實際上,繼續把它看作是函數也無妨。

      Java的方法決定了一個對象能夠接受什麼樣的消息。方法的基本組成部分包括:名稱,參數,返回值和方法體。下面是它基本的形式:

ReturnType methodName(/** Argument list*/){
    /** Method body */
}
  • 返回類型描述的是在調用方法之後從方法返回的值。參數列表給出要傳給方法的信息的類型和名稱。方法名和參數列表(它們合起來被稱爲 方法簽名) 唯一地表示出某個方法。
  • Java中的方法只能做作爲類的一部分來創建。方法只有通過對象才能被調用,並且這個對象必須能執行這個方法調用。如果試圖在某個對象上調用它並不具備的方法,那麼編譯時就會得到一條錯誤信息。

5.1.參數列表

  • 方法的參數列表指定要傳遞給方法什麼樣的信息。正如你可能料想的那樣,這些信息像Java中其他信息一樣,採用的都是對象形式。因此,在參數列表中必須指定每個所傳遞對象的類型及名字。像Java中任何傳遞對象的場合一樣,這裏傳遞的時機上也是引用,並且引用的類型必須正確。如果參數被設爲 String 類型,則必須傳遞一個String對象,否則,編譯器將拋出錯誤。
  • 若返回類型是 void ,return 關鍵字的作用只是用來退出方法。因此,沒有必要到方法結束時才離開,可在任何地方返回。但如果返回類型不是void ,那麼無論在何處返回,編譯器都會強制返回一個正確類型的返回值。
  • 你可能覺得: 程序似乎只是一系列帶有方法的對象組合,這些方法以其他對象爲參數,併發送消息給其他對象。

 

6創建一個Java程序

  • 名字可見性 Java採用一種全新的方法避免模塊名字重複的衝突呢? Java設計者希望程序員反過來使用自己的Internet域名。
  • 運用其他構件  import 關鍵字來準確地告訴編譯器你想要的類是什麼。
  • static 當聲明一個事物是static時,就意味着這個域或方法不會與包含它的那個類的任何對象關聯在一起。所以,即使從未創建一個對象,也可以調用其static方法或訪問其static域。通常,你必須創建一個對象,並用它來訪問數據或者方法。因爲非static域和方法必須知道它們一起運作的特定對象。
  • static 方法的一個重要用法就是在不創建任何對象的前提下就可以調用它。

6.1.註釋和嵌入式文檔

  1. Java有倆種註釋風格。一種是傳統的C語言風格的註釋__C++也繼承了這種風格。如下
    /** This is a comment
     *  that continues
     *  across lines
     */

    2.第二種風格也來源於C++。單行註釋 如下

// this is a one-line comment

 

6.2.註釋文檔

  • Javadoc 是用於提取註釋的工具,他是JDK安裝的一部分。Javadoc命令都只能在 /** 註釋中出現,和通常一樣,註釋結束於 */
  • Javadoc 只能爲 public(公開的) 和 protected (受保護的) 成員進行文檔註釋。
  • Javadoc 中一些標籤的使用
  • @see: 引用其他類
  • {@link package.class#member label} 該標籤與@see及其相似,只是它只能用於行內,並且使用 label 作爲超鏈接文本而不用 See Also
  • {@docRoot} 該標籤產生到文檔根目錄的相對路徑,用於文檔樹頁面的顯式超鏈接
  • {@inheritDoc} 該標籤從當前這個類的最直接的基類中繼承相關文檔到當前的文檔註釋中
  • @version 可以是你認爲合適包含在版本說明中重要信息
  • @author 作者姓名,也可以是電子郵箱或者是其他任何適宜的信息
  • @since 指定程序代碼最早使用的版本
  • @param 用於方法文檔中 表示傳入方法參數
  • @return 用於方法文檔中 表示方法返回值類型等信息
  • @description 用來描述返回值的含義 ,可以延續數行
  • @throws 異常,它們是由某個方法調用失敗而拋出的對象
  • @deprecated 該標籤用於指出一些舊特性已由改進的新特性所取代,建立用戶不要在使用這些舊特性,因爲在不就將來它們很可能會被刪除。 在JavaSE5中 @deprecated 被 @Deprecated註解所取代

 

6.3.編碼風格 

  • 在 Java編程語言編碼約定 中,代碼風格是這樣規定的 類名的首字母大寫,如果類名由幾個單詞構成,那麼把它們拼在一起,其中每個內部單詞的首字母都採用大寫形式,如下
class AllTheColorsOfTheRainbow{
    //class body
}
  • 這種風格被稱爲 駝峯風格 
  • 幾乎所有的內容__方法,字段(成員變量),以及對象引用引用名稱等,公認的風格與類的風格一樣,只是標識符的第一個字母採用小寫。 例如
public class AllTheColorsOfTheRainbow {
    int anIntegerRepresentingColors;
    void changeTheHueOfTheColor(int newHue){
        //method body
    }
    
    //class body
}

7.總結

  • 通過本章的學習,可以對Java語言以及一些基本思想也有了一個總體的認識。
  • 從Java的內存存儲到什麼地方 到 八大基本數據類型  到 Java作用域,對象作用域  到類(class) 字段和方法 , 到 static關鍵字 到  Javadoc註釋文檔 到類名 方法名名稱如何起 都有了一定簡單的認識

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章