如果我們說另一種不同的語言,那么我們就會發(fā)覺一個有些不同的世界。——Luduing Wittgerstein(1889-1951)
Java是基于C++的,C++和Java都是混合/雜合型語言。雜合型語言允許多種編程風格;C++之所以成為一種雜合型語言主要是因為它支持與C語言的向后兼容。因為C++是C的一個超集,包括許多C語言不具備的特性,這些特性使C++在某些方面顯得過于復雜。
用引用操作對象
一切都看作對象,操縱的標識符實際上是對象的一個“引用(reference)”。例如String s;這里所創(chuàng)建的只是引用,并不是對象。此時向s發(fā)送一個消息,就會返回一個運行時錯誤。因此一種安全的做法是:創(chuàng)建一個引用的同時便進行初始化。String s="abcd";(Java語言的一個特性:字符串可以用帶引號的文本初始化)。
必須由你創(chuàng)建所有對象
new關鍵字的意思是“給我一個新對象”。String s = new String("abcd");它不僅表示了“給我一個新的字符串”,而且通過提供一個初始字符串,給出了怎樣產(chǎn)生這個String的信息。
存儲到什么地方
- 寄存器。這是最快的存儲區(qū),位于處理器的內(nèi)部。由于寄存器數(shù)量極其有限,所以寄存器根據(jù)需求進行分配。不能直接控制(C和C++允許向編譯器建議寄存器的分配)。
- 堆棧。位于通用RAM(隨機訪問存儲器)中,但通過堆棧指針可以從處理器那里獲得直接支持。堆棧指針向下移動,則分配新的內(nèi)存;向上移動,則釋放那些內(nèi)存。僅次于寄存器。Java系統(tǒng)必須知道存儲在堆棧內(nèi)所有項的確切生命周期,以便上下移動堆棧指針。這一約束限制了程序的靈活性,所以雖然Java某些數(shù)據(jù)存儲在堆棧中——特別是對象引用,但是Java對象并不存儲其中。
- 堆。一種通用的內(nèi)存池(也位于RAM區(qū)),用于存放所有的Java對象。堆不同于堆棧的好處是:編譯器不需要知道存儲的數(shù)據(jù)在堆里存活多長時間。用堆進行存儲分配和清理可能比用堆棧進行存儲分配需要更多的時間(如果確實可以在Java中像C++中那樣在棧中創(chuàng)建對象)。
- 常量存儲。常量值通常直接存放在程序代碼內(nèi)部,這樣做是安全的,因為它們永不會被改變。可以選擇將其存放在ROM(只讀存儲器)中。
-
非RAM存儲。如果數(shù)據(jù)完全存活于程序之外i,那么它可以不受程序的任何控制,在程序沒有運行時也可以存在。兩個例子如
流對象和持久化對象。
基本類型
對于這些類型,new創(chuàng)建一個對象——特別是小的,簡單的變量,往往不是很有效,因此,Java采取與C和C++相同的方法。創(chuàng)建一個并非是引用的“自動”變量,這個變量直接存儲“值”并置于堆棧中,因此更加高效。
Java要確定每種基本類型所占存儲空間的大小。這種所占存儲空間大小的不變性是Java程序比用其他大多數(shù)語言編寫的程序更具可移植性的原因之一。
| 基本類型 | 包裝器類型 | 大小 |
|---|---|---|
| boolean | Boolean | - |
| char | Character | 16-bit |
| byte | Byte | 8 bits |
| short | Byte | 16 bits |
| int | Integer | 32 bits |
| long | Long | 64 bits |
| float | Float | 32 bits |
| double | Double | 64 bits |
| void | Void | - |
boolean類型所占存儲空間的大小沒有明確指定,僅定義為能夠取字面值true和false。
高精度數(shù)字
Java提供了兩個用于高精度計算的類:BigInteger和BigDicimal。
BigInteger支持任意精度的整數(shù)。BigDicimal支持任意精度的定點小數(shù)。
Java中的數(shù)組
在C和C++中使用數(shù)組很危險,因為數(shù)組就是內(nèi)存塊,如果一個程序要訪問其自身內(nèi)存卡塊之外的數(shù)組,或在數(shù)組初始化前使用內(nèi)存,都會產(chǎn)生難以預料的后果。Java確保數(shù)組會被初始化,而且不能在它的范圍之外被訪問。這種范圍檢查,是以每個數(shù)組上少量的內(nèi)存開銷及運行時的下標檢查為代價的。當創(chuàng)建一個數(shù)組對象時,就是創(chuàng)建了一個引用數(shù)組,并且每個引用都會自動被初始化為一個特定值null。如果試圖使用一個還是null的引用,在運行時就會報錯。
永遠不需要銷毀對象
作用域
在C、C++和Java中,作用域(scope)由花括號的位置決定。在作用域里定義的變量只可用于作用域結束之前。盡管以下代碼在C和C++中是合法的,但是在Java中卻不能這樣書寫:
{
int x=12;
{
int x=96;
}
}
編譯器會報告變量x已經(jīng)定義過。
對象的作用域
Java對象不具備和基本類型一樣的生命周期。當用new創(chuàng)建一個Java對象時,它可以存活于作用域之外。
{
String s= new String("Abcs");
}
引用s在作用域的終點就消失了。然后s指向的String對象仍繼續(xù)占據(jù)內(nèi)存空間。事實上,由new創(chuàng)建的對象,只要你需要,就會一直保留下去。Java有一個垃圾回收器,用來監(jiān)視用new創(chuàng)建的所有對象,并辨別那些不會再被引用的對象。隨后,釋放這些對象的內(nèi)存空間,以便供其他新的對象使用。
創(chuàng)建新的數(shù)據(jù)類型:類
class關鍵字表示一個新類型的對象是什么樣子的。
字段和方法
一旦定義了一個類,就可以在類中設置兩種類型的元素:字段(數(shù)據(jù)成員)和方法(成員函數(shù))。如果字段是對某個對象的引用,那么必須初始化該引用,以便與一個實際的對象相關聯(lián)。每個對象都有用來存儲其字段的空間;普通字段不能在對象間共享。
基本成員默認值
若類的某個成員是基本數(shù)據(jù)類型,即使沒進行初始化,Java也會確保它獲得一個默認值。
| 基本類型 | 默認值 |
|---|---|
| boolean | false |
| char | '\u0000'(null) |
| byte | (byte)0 |
| short | (short)0 |
| int | 0 |
| long | 0L |
| float | 0.0f |
| double | 0.0d |
當變量作為類的成員時,Java才確保給定其默認值(C++沒有此功能),然而上述確保初始化的方法不適用于“局部”變量。如果忘記對局部變量初始化,Java會在編譯時返回一個錯誤(C++編譯器給予警告)。
方法、參數(shù)和返回值
方法的基本組成包括:名稱、參數(shù)、返回值和方法體。方法名和參數(shù)列表(它們合起來被稱為“方法簽名”)唯一地標識出某個方法。
Java中的方法只能作為類的一部分來創(chuàng)建。方法只有通過對象才能被調(diào)用(或針對類的調(diào)用),且這個對象必須能執(zhí)行這個方法調(diào)用。這種調(diào)用方法的行為通常被稱為發(fā)送消息給對象。
參數(shù)列表
方法的參數(shù)列表指定要傳遞給方法什么樣的信息,采用的都是對象形式。因此,在參數(shù)列表中必須指定每個所傳遞的對象的類型及名字。這里的傳遞實際上也是引用(基本數(shù)據(jù)類型是傳遞的值)。
static關鍵字
執(zhí)行new來創(chuàng)建對象時,數(shù)據(jù)存儲空間才被分配。有兩種情形是上述方法無法解決的。一種情形是,只想為某特定域分配單一存儲空間,而不去考慮究竟要創(chuàng)建多少對象,甚至不創(chuàng)建對象。另一種情況是,希望某個方法不與包含它的類的任何對象關聯(lián)在一起。也就是說,不創(chuàng)建對象也能調(diào)用這個方法。
當聲明一個事務是static時,就意味著這個域或方法不會與包含它的那個類的任何對象實例關聯(lián)在一起。對于static方法,不能直接訪問非static方法,必須要與某一特定對象關聯(lián)。類數(shù)據(jù)和類方法代表那些數(shù)據(jù)和方法是作為整個類而存在的。即使創(chuàng)建了多個對象實例,類數(shù)據(jù)也只有一份存儲空間,可以通過對象訪問也可以通過類名直接引用。
static方法的一個重要用法就是在不創(chuàng)建任何對象的前提下調(diào)用它,這對定義main()方法很重要,這個方法是運行一個應用時的入口點。