基於《Java編程思想》第四版java
「程序就是算法加數據結構」,而算法就是控制語句加操做符,編寫一個程序就是使用控制語句加操做符去操做數據結構,所以我從Java的控制語句、操做符以及如何組織數據結構開始入手。由於有C/C++的基礎,因此難免會以對比的方式去理解Java。程序員
除了沒有goto
,Java的控制流程的關鍵字和C++是同樣的,很好理解。不過Java中的break
和continue
除了C++的正常做用外(跳出或繼續當前循環),還有相似C++中goto
的功能,可是使用上是有限制的,即標籤與for
、while(){}
、do{}while()
或switch
之間不能有其餘語句,不然就會有編譯錯誤。算法
break
跳轉到標籤後,會直接跳過標籤後緊跟着的循環或者switch
代碼,而不是從標籤位置從新開始執行。int[] a = {1,2,3,4}; Label: // 這裏不能有任何語句 for( int i : a ){ System.out.println("loop 1 i = " + i); for( int j : a ){ System.out.println("loop 2 j = " + j); break Label; } } // break Lable後會直接執行下面的代碼,而不是繼續循環 System.out.println("loop over");
continnue
跳轉到標籤後,會繼續執行標籤後緊跟着的循環代碼,但並不是重頭開始執行而是從本來的基礎上繼續執行int[] a = {1,2,3,4}; Label: // 這裏不能有任何語句 for( int i : a ){ System.out.println("loop 1 i = " + i); for( int j : a ){ System.out.println("loop 2 j = " + j); continue Label; } } System.out.println("loop over");
運行以上代碼就會發現break Label
的含義就是跳出Label
標識的循環,而continue Label
的含義是繼續循環Label
標識的循環,這和C++的goto
是不一樣的。C++中的goto
會將讓程序執行流回到Label
的位置,從新執行Label
後的代碼。編程
Java多了一個無符號右移操做符>>>
,其餘都和C/C++同樣,也很好掌握。不過Java中沒法進行操做符重載,所以理論上操做符應該只能做用於數值類型。但實際上,Java的String
類型也可使用=
、+
和+=
操做符,我想應該是由於字符串的賦值和拼接是很常見的操做,因此Java就在內部偷偷給String
類型作了這些操做符的重載。這雖然帶來了必定的便利,可是由於String
類型的其餘操做符並無重載,因此讓我感受不一致,比較難受。好比下面這段代碼,由於String
的==
並未重載,因此並不會打印"same string"數據結構
String s1 = new String("hello"); String s2 = new String("hello"); if( s1 == s2 ){ System.out.println(「same string」); }
在C++中,則能夠經過操做符重載,使得std::string
類型可使用==
操做符比較是否爲相同字符串,很一致。函數
還有一點,Java中並無sizeof
操做符。我想這是由於Java不想讓程序員去關注內存分配,天然也就無需關心類型大小,再者基礎類型的大小在Java中是固定的,因此sizeof
就無用武之地了。C中分配內存的函數,如malloc
等,都是須要指定大小的,且基礎類型在不一樣平臺的大小多是不同大的,所以必須有sizeof
計算大小。oop
Java有如下基礎類型
這些基礎類型的大小都是固定的,並且全部數值類型都是有符號的。學習
Java經過class
關鍵字來自定義類型,其結構與C++相似,只是不須要在}
後加;
。指針
class MyType{ ... }
C++中的自定義類型除非指定繼承不然是沒有繼承關係的,可是在Java中全部類型都隱式繼承自Object
。Java中有不少已經定義好的類型,好比基礎類型的包裝器類型、String
等等,學習並使用這些已經定義好的類型是水磨工夫,起初瞭解一下就能夠了。code
Java的函數的定義語法和C++是如出一轍的,可是函數只能在類型的命名空間裏即只能在
class {這裏面}
定義,而不能在全局命名空間中定義。函數在Java中應該叫方法,不知道叫函數會不會有誤解。
Java的自定義類型中能夠包含其餘類型的變量或者繼續定義類型(內部類)。其餘類型的變量,C++中叫成員變量,但彷佛Java中叫域。
Java實例化類型的語法和C++如出一轍,可是有一些限制。
new
實例化int x = 1;
String
類型等,能夠直接賦值(本質上是編譯器幫你作了一次隱式轉換),或使用new
實例化Integer n1 = 1; Integer n2 = new Integer(1); String s1 = "hello"; String s2 = new String("hello"); // 不推薦這麼用,轉換後的字節碼更多
new
關鍵字MyType m = new MyType(1); // MyType m = 1; 不會進行一次隱式轉換,編譯報錯
能夠感受到很強烈的不一致!!
基礎類型的變量空間存儲的是真實數值,而其餘類型的變量空間存儲的是實例化對象的引用。Java中的引用和C++的引用並非一個意思,Java中的引用更像是C++中的指針。在C++中,引用是一個實例對象的別名,一旦肯定就沒法變動其引用的對象,可是在Java中能夠變動引用的實例化對象,好比
Integer a = new Integer (1); a = new Integer(2);
在函數傳參中,這點就更明顯了,好比下面的函數,咱們叫a
和b
是引用,但實際呢,這只是值傳遞,swap()
中的交換並不會影響實際對象的值。整個函數就是交換了一下a
和b
這兩個局部變量指向的對象而已。
void swap(Integer a, Integer b){ Integer tmp = a; a = b; b = tmp; }
就相似於如下C++代碼
void swap(int* a, int* b){ int* tmp = a; a = b; b = tmp; }
從上面看所謂對象的引用其實就是把對象的地址值(不是內存地址,只須要是一個惟一位置的標識便可)保存到了變量空間裏。從這個角度去理解,基礎類型的變量和其餘類型的變量存儲的東西能夠認爲是同樣的。Java中只有值傳遞。
和C++同樣,Java也有針對類、方法、域的訪問權限控制。Java除了public
、proteceted
和private
這些權限外,還有一種包訪問權限。當不帶另外三個權限關鍵字時,就是包訪問權限了。在Java中能夠將一些源文件定義爲一個包,所以就有了包訪問權限,即同一包內能夠訪問。Java中的包相似於C++的動態庫,C++中雖然沒有明確說包(庫)訪問權限,但其實是有的,好比Linux下能夠經過連接時的參數version-script
指定動態庫的導出符號,那些未導出的符號就是包(庫)訪問權限了。
一個.java
源文件中只能有一個public
類,且源文件名必須和這個public
類的名字保持一致。其餘類只能是包訪問權限,固然內部類是不受這個限制的,能夠是任意權限。每一個類型均可以有一個public static void main(String[] agrs)
,這是執行的入口。由於函數都是在類的命名空間裏,因此存在多個main()
也是能夠的,指定執行的類就會調用對應的main()
。
由於IDE的強大,因此不少東西只須要腦子裏有點印象,作到寫代碼時看到錯誤提示就能想到是爲何就能夠了,熟能生巧。