1. 程式人生 > >Java學習點滴——初識Java

Java學習點滴——初識Java

組織 訪問 我們 類型 就是 賦值 main script c++類

基於《Java編程思想》第四版

前言

“程序就是算法加數據結構”,而算法就是控制語句加操作符,編寫一個程序就是使用控制語句加操作符去操作數據結構,因此我從Java的控制語句、操作符以及如何組織數據結構開始入手。因為有C/C++的基礎,所以不免會以對比的方式去理解Java。

控制語句

除了沒有goto,Java的控制流程的關鍵字和C++是一樣的,很好理解。不過Java中的breakcontinue除了C++的正常作用外(跳出或繼續當前循環),還有類似C++中goto的功能,但是使用上是有限制的,即標簽與forwhile(){}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計算大小。

類型

Java有以下基礎類型
技術分享圖片
這些基礎類型的大小都是固定的,而且所有數值類型都是有符號的。

Java通過class關鍵字來自定義類型,其結構與C++類似,只是不需要在}後加;

class MyType{
     ...
}

C++中的自定義類型除非指定繼承否則是沒有繼承關系的,但是在Java中所有類型都隱式繼承自Object。Java中有很多已經定義好的類型,比如基礎類型的包裝器類型、String等等,學習並使用這些已經定義好的類型是水磨工夫,起初了解一下就可以了。

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);

在函數傳參中,這點就更明顯了,比如下面的函數,我們叫ab是引用,但實際呢,這只是值傳遞swap()中的交換並不會影響實際對象的值。整個函數就是交換了一下ab這兩個局部變量指向的對象而已。

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除了publicprotecetedprivate這些權限外,還有一種包訪問權限。當不帶另外三個權限關鍵字時,就是包訪問權限了。在Java中可以將一些源文件定義為一個包,因此就有了包訪問權限,即同一包內可以訪問。Java中的包類似於C++的動態庫,C++中雖然沒有明確說包(庫)訪問權限,但實際上是有的,比如Linux下可以通過鏈接時的參數version-script指定動態庫的導出符號,那些未導出的符號就是包(庫)訪問權限了。

文件組織

一個.java源文件中只能有一個public類,且源文件名必須和這個public類的名字保持一致。其他類只能是包訪問權限,當然內部類是不受這個限制的,可以是任意權限。每個類型都可以有一個public static void main(String[] agrs),這是執行的入口。因為函數都是在類的命名空間裏,所以存在多個main()也是可以的,指定執行的類就會調用對應的main()

結語

因為IDE的強大,所以很多東西只需要腦子裏有點印象,做到寫代碼時看到錯誤提示就能想到是為什麽就可以了,熟能生巧。

Java學習點滴——初識Java