1. 程式人生 > >Java程式設計思想(1)

Java程式設計思想(1)

第1章 物件導論

1 Java用三個關鍵字在類的內部設定邊界:public,protected,private

2 如果組合是動態發生的,那麼它通常被稱為聚合。組合經常被視為“has-a”關係。繼承經常被視為"is-a"關

3 繼承用關鍵字extends。子類改變基類的方法稱為"覆蓋"(overriding)

4 Java採用動態繫結。把將匯出類看做是它的基類的過程稱為向上轉型

5 Java中所有的類都繼承自單一的基類,即Object

6 Java採用動態記憶體分配方式,即建立新物件時要使用new關鍵字來建立例項

7 Java提供了“垃圾回收”機制

 

 

 

 

第2章 一切都是物件

1 String s ;  該語句只是建立一個引用,s並沒有跟任何事物相關聯。如果相關聯一個物件,通常用new操作符實現,如下

               String s  =  new String("abc") ;

2 程式執行時,物件會儲存在如下的五個地方

  • 暫存器最快的儲存器,因為它在處理器內部。但暫存器數量有限
  • 堆疊:位於通用RAM(隨機訪問儲存器),通過堆疊指標從處理器獲得直接支援。速度僅次於暫存器
    物件引用一般存在這裡,但是java物件並不存在這裡
  • :通用的記憶體池(也位於RAM區),用於存放所有的java物件
  • 常量儲存:常量值通常直接存放在程式程式碼內部。
  • 非RAM儲存:如果資料完全存活於程式之外,那麼它可以不受程式的任何控制,在程式執行時也可以存在。

3 Java不是用new來建立變數,而是建立一個並非是引用的"自動"變數,這個變數直接儲存"值"並置於堆中。

4 Java要確定每種基礎型別所佔儲存空間的大小,並不會隨機器硬體架構的變化而變化,如下

5 boolean型別所佔儲存空間的大小沒有明確指定,僅定義為能夠取字面值true或false

6 java提供了兩個用於高精度計算的類:BigIntegerDecimal

7 java會確保陣列會被初始化,並且不能在它的訪問之外被訪問。

8 儘管以下程式碼在C和C++是合法的,但java不能這麼寫,如下所示,x會被java判斷為定義了2次而報錯

{
	int x = 12;
	{
		int x = 96;   // x被重定義
	}
}

9 java物件不具備和基礎型別一樣的生命週期,當new建立一個物件時,它可以存活於作用域之外

{
    String s = new String("a string");
}

引用s會在作用域外就消失了,但s指向的String物件仍繼續佔據記憶體空間。垃圾回收器會監視用new建立的所有物件,並辨別那些不會再被引用的物件

10 java用class定義一個新類,可以用new建立這個類的物件。要使用該物件的成員變數或成員函式,在物件引用的名稱後面緊跟一個句點,再接著成員名稱或成員函式,即objectReference.member,如下

    class DataOnly {
		int i;
		double d;
		boolean b;
	}
	DataOnly data = new DataOnly();
	data.i = 1;
	data.d = 1.2;
	data.b = false;

11 類的成員變數是基礎資料型別時,即使沒有初始化,java也會確保成員變數有個預設值,預設值如下

12 區域性變數不會有初始化,所以在使用前一定要賦值,不然java會在編譯時就報錯

13 java的基本組成部分包括:返回型別,函式名稱,引數和方法體,如下

             ReturnType  methodName(/*Argument lsit */) {

                        /* Method  body  */

             }

14 Java設計者希望程式設計師反過來使用自己的Internet域名宣告庫名。import指示編譯器匯入一個包,即一個類庫。如

              import  java.util.ArrayList ; 

15 當用new建立物件時,資料儲存空間才會被分配,其方法才供外界呼叫。

16 當宣告一個事物是static時,就意味著這個域或方法不會與包含它的那個類的任何物件例項有關聯。無須建立該類的任何物件,也可以呼叫其static方法或訪問其static變數。即類成員和類方法。如下

class StaticTest{
    static int i = 47;
    static void fun(){}
}
 
int a = StaticTest.i;    // 無須建立類物件,即可呼叫
StaticTest.fun()        // 無須建立類物件,即可呼叫

該類的所有物件例項都共享同一個類成員和類方法。

17 類的名字必須和檔名相同。如果建立一個獨立執行的程式,那麼檔案中必須存在某個類和檔案同名且該類必須包含一個名為main()的函式

18 java有兩種註釋方法,/**/ 和 //

19 java的程式碼風格:類名的首字母要大寫,如果類名是由幾個單詞構成,就並在一起,每個單詞的首字母都大寫,不用下劃線分隔,如下 AllTheColorsOfTheRainbow,即駝峰風格。方法,欄位及物件引用名稱都採用首字面小寫。

 

 

 

 

第3章 操作符

1 String類支援操作符"+"和"+="

2 String後面緊跟一個"+",而"+"後面跟著一個非String型別的元素,編譯器會把這個非String型別的元素轉換為String型別。

3 基礎型別儲存了實際的數值,並非指向一個物件的引用

4 在為物件賦值的時候,操作的是對物件的引用。這種現象被稱作“別名現象”

class Tank {
	int level;
}

public class HelloDate {

	public static void main(String[] args){
		Tank t1 = new Tank();
		Tank t2 = new Tank();
		t1.level = 42;
		t2.level = 27;
		t1 = t2;    // 是將t2物件的引用賦值給t1
		t1.level = 34;  // t1的修改其實就是對t2的修改
		System.out.println("t1 = "+t1.level+", t2 = "+t2.level);
	}
}

5 函式呼叫中的別名問題,即修改形參會影響到實參,如下

class Letter {
	char c;
}

public class HelloDate {

	static void f(Letter y){
		y.c = 'z';
	}
	
	public static void main(String[] args){
		Letter x = new Letter();
		x.c = 'a';
		System.out.println("1: x.c="+x.c);    // 1: x.c=a
		f(x);   // 傳遞的是物件x的引用,所以函式修改的也會影響到物件x
		System.out.println("2: x.c="+x.c);    // 2: x.c=z
	}
}

6 java支援字首式自增,字尾式自增,字首式自減,字尾式自減,如下

int i = 1;
System.out.println("i : "+i);       // i : 1
System.out.println("++i : "+ ++i);  // ++i : 2
System.out.println("i++ : "+i++);   // i++ : 2
System.out.println("i : "+i);       // i : 3
System.out.println("--i : "+ --i);  // --i : 2
System.out.println("i-- : "+i--);   // i-- : 2
System.out.println("i : "+i);       // i : 1

7 用關係操作符 == 和 != 比較物件時,比較的式是物件的引用。物件如果要比較內容可以用成員函式equals(),但是equals()預設是比較引用,在自定義的類裡需要覆蓋equals()

Integer n1 = new Integer(45);
Integer n2 = new Integer(45);
System.out.println(n1 == n2);       //false
System.out.println(n1.equals(n2));  //true


			
// equals()預設是比較引用,在自定義的類裡需要覆蓋equals()

class Letter {
	char c;
	public Letter(char c){
		this.c = c;
	}
}

Letter t1 = new Letter('a');
Letter t2 = new Letter('a');
System.out.println(t1 == t2);       //false
System.out.println(t1.equals(t2));  //false

8 當使用邏輯操作符時,會有一種“短路”形象,即一旦能夠明確無誤地確定整個表示式值就不再計算邏輯表示式餘下部分。如下所示,因為test2(2)為false,則整條邏輯表示式已明確為false,test3()無須執行,輸出結果為

test1(0)

result:true

test2(2)

result:false

expression is false

        static boolean test1(int val){
		System.out.println("test1("+val+")");
		System.out.println("result:"+(val<1));
		return val < 1;
	}
	static boolean test2(int val){
		System.out.println("test2("+val+")");
		System.out.println("result:"+(val<2));
		return val < 2;
	}
	static boolean test3(int val){
		System.out.println("test3("+val+")");
		System.out.println("result:"+(val<3));
		return val < 3;
	}
	
	public static void main(String[] args){
		boolean b = test1(0) && test2(2) && test3(2);
		System.out.println("expression is "+b);
	}

9 直接常量

                int i1 = 0x2f;   // 十六進位制
		System.out.println("i1: "+Integer.toBinaryString(i1));
		int i2 = 0X2F;   // 十六進位制
		System.out.println("i2: "+Integer.toBinaryString(i2));
		int i3 = 0177;   // 八進位制
		System.out.println("i3: "+Integer.toBinaryString(i3));
		char c = 0xffff;
		System.out.println("c: "+Integer.toBinaryString(c));
		byte b = 0x7f;
		System.out.println("b: "+Integer.toBinaryString(b));
		short s = 0x7fff;
		System.out.println("s: "+Integer.toBinaryString(s));
		long n1 = 200L;
		long n2 = 200l;
		long n3 = 200;
		float f1 = 1;
		float f2 = 1F;
		float f3 = 1f;
		
		double d1 = 1d;
		double d2 = 1D;

10 指數記數法。編譯器通常會把指數作為雙精度數處理

                float expFloat = 1.39e-43f;
		expFloat = 1.39E-43f;
		System.out.println(expFloat);  //1.39E-43
		double expDouble = 47e47d;
		double expDouble2 = 47e37;
		System.out.println(expDouble);  //4.7E48

11 按位操作符用來操作基礎資料型別的單個位元,即二進位制。與(&),或(|),異或(^),非(~)。並且可以和等號聯合使用(&= , |= , ^= , ~= )

12 移位操作符操作物件的二進位制,左移位操作符(<<)能按照操作符右側指定的位數將操作符左邊的運算元向左移動(在低位補0),右移位操作符(>>)能按照操作符右側指定的位數將操作符左邊的運算元向右移動。“有符號”右移位操作符使用"符號擴充套件":若符號為正則在高位插入0,若符號為負則在高位插入1”無符號“右移位操作符(>>>)使用零擴充套件,即無論正負都在高位插入0.

		int i = -12;
		System.out.println(Integer.toBinaryString(i));     // 11111111111111111111111111110100
		System.out.println(Integer.toBinaryString(i>>3));  // 11111111111111111111111111111110
		System.out.println(Integer.toBinaryString(i>>>3)); // 11111111111111111111111111110
		int j = 100;
		System.out.println(Integer.toBinaryString(j));     // 1100100
		System.out.println(Integer.toBinaryString(j>>3));  // 1100
		System.out.println(Integer.toBinaryString(j>>>3)); // 1100 
		int k = 5;
		System.out.println(Integer.toBinaryString(k));     // 101
		System.out.println(Integer.toBinaryString(k << 2));// 10100

13 三元操作符 if-else,也被稱為條件操作符。  boolean-exp ? value0 : value1  當boolean-exp為true時計算value0,若為false則計算value1

14 型別轉換的一種方法:將希望得到的資料型別置於圓括號中,放在要進行型別轉換的值的左邊,即(type) value,如下

int t = 0;
long n = (long)t;   // 將t從int型別轉換為long型別

15 java允許我們把任何基本資料型別轉換成別的基本資料型別,但布林型除外,布林型不允許進行任何型別的轉換處理。“類”資料型別不允許進行型別轉換,如果要轉換要採用特殊的方法。

16 將浮點數轉換為整型值,資料會被截掉,而不是四捨五入。如下所示,輸出都是0

		double above = 0.7,below = 0.4;
		float fabove = 0.7f,fbelow = 0.4f;
		System.out.println("(int)above:"+((int)above));
		System.out.println("(int)below:"+((int)below));
		System.out.println("(int)fabove:"+((int)fabove));
		System.out.println("(int)fbelow:"+((int)fbelow));

如果想要得到四捨五入結果可以使用java.lang.Math的round()方法                

17 表示式只有基礎資料時,表示式中出現的最大的資料型別決定了表示式最終結果的資料型別,如float值和double值相乘,結果就是double值。int值和long值相加則結果是long值

 

 

 

 

第4章 控制執行流程

1 java支援if-else,while,do-while,for,return,break以及switch。java並不支援goto語句,但仍然可以進行類似goto那樣的跳轉。

2 if-else 語句

	static int test(int v1,int v2){
		if(v1 > v2){
			return 1;
		}else if(v1 == v2){
			return 0;
		}else{
			return -1;
		}
	}

3 while,do-while和for用來控制迴圈,有時會被劃分為迭代語句。while會比do-while少執行一次

// while
while(boolean-expression)
    statement

// do-while
do 
    statement
while(boolean-expression);

// for
for(initialization;boolean-expression;step)
    statement

4 for語句中可以定義多個變數,用逗號隔開,但它們必須具有相同的型別

for(int i=1,j=i+10;i<5;i++,j=i+2){
    System.out.println("i = "+i+",j = "+j);
}

5 Java SE5引入了foreach語法用於陣列和容器,不必建立int變數去對由訪問項構成的序列進行計數,foreach自動產生每一項。如 for( float item : array )

		Random r = new Random(47);
		float f[] = new float[10];
		for(int i=0;i<10;i++)
			f[i] = r.nextFloat();
		for(float x:f){            // foreach語法
			System.out.println(x);
		}

任何返回一個數組的方法都可以使用foreach。如String類有一個方法toCharArray(),它返回一個char陣列。

		for(char c:"An African Swallow".toCharArray()){
			System.out.print(c+" ");
		}

6 break用於強行退出迴圈,不執行迴圈中剩餘的語句。而continue則停止執行當前的迭代,然後直接開始下一次迭代。

7 goto仍是Java中的一個保留字,但在語言中並未使用它;Java不支援goto。但採用標籤機制通過break和continue來實現類似跳轉的操作。

	public static void main(String[] args){
		int i = 0;
		outer:    // 標籤
			for(;true;){
				innert:   // 標籤
					for(;i<10;i++){
						System.out.println("i = "+i);
						if(i == 2){
							System.out.println("continue");
							continue;
						}
						if(i == 3){
							System.out.println("break");
							i++;
							break;
						}
						if(i == 7){
							System.out.println("continue outer");
							i++;
							continue outer;  // 跳轉至outer繼續進行
						}
						if( i == 8){
							System.out.println("break outer");
							break outer;     // 跳出outer
						}
						for(int k=0;k<5;k++){
							if(k == 3){
								System.out.println("continue inner");
								continue innert;
							}
						}
					}
			}
	}

在Java裡需要使用標籤的唯一理由是因為有迴圈巢狀存在,而且想從多層巢狀中break或continue。

8 switch裡的選擇因子必須是int或char那樣的整數值,或enum,不能把浮點數或字串作為選擇因子使用

switch(integeral-selector){
    case integral-value1: statement;break;
    case integral-value2: statement;break;
    case integral-value3: statement;break;
    case integral-value4: statement;break;
    // ...
    default: statement;break;    
}
	public static void main(String[] args){
		Random r = new Random(47);
		for(int i=0;i<100;i++){
			int c = r.nextInt(26)+ 'a';
			System.out.print(((char)c)+". "+c+": ");
			switch(c){
			case 'a':
			case 'e':
			case 'i':
			case 'o':
			case 'u':System.out.println("vowel");break;
			case 'y':
			case 'w':System.out.println("Sometimes a vowel");break;
			default:System.out.println("consonant");break;
			}
		}
	}

 

 

 

 

第5章 初始化與清理

1 構造器的名稱必須與類名完全相同。所以"每個方法首字母小寫"的編碼風格並不適用於構造器。構造器也沒有返回值

2 建立物件時new Xxxx()將會為物件分配儲存空間,並呼叫相應的構造器。

3 不接受任何引數的構造器叫做預設構造器

class Rock2{
	Rock2(int i){
		System.out.print("Rock "+i+" ");
	}
}

public class HelloDate {
	
	public static void main(String[] args){
		for(int i=0;i<8;i++)
			new Rock2(i);
	}
}

4 方法過載指函式名一樣,但引數型別,引數個數或引數順序不一樣。返回值有無及其型別不作為判斷

class Tree {
	int height;
	Tree(){
		System.out.print("Planting a seedling");
		height = 0;
	}
	Tree(int intialHeight){
		height = intialHeight;
		System.out.print("Creating new Tree that is "+height+" feet tall");
	}
	void info(){
		System.out.print("Tree is "+height+" feet tall");
	}
	void info(String s){
		System.out.print(s+": Tree is "+height+" feet tall");
	}
}

5 如果你寫的類中沒有構造器,則編譯器會自動幫你建立一個預設構造器。

6 通過關鍵詞this返回當前物件的引用

class Rock2{
	int i = 0;
	Rock2 increment(){
		i++;
		return this;
	}
}

7 構造器呼叫構造器,可以通過this。在構造器內使用this呼叫一個構造器,但卻不能呼叫兩個

class Rock2{
	int petalCount = 0;
	String s = "initial value";
	Rock2(int petals){
		petalCount = petals;
	}
	Rock2(){
		this("a",1);
		this(1);     // error , 用this呼叫一個構造器,但卻不能呼叫兩個
	} 
	Rock2(String s,int petals){
		this(petals);   // 等同於呼叫Rock2(int petals)
	}
	
}

8 static函式裡是沒有this,在static函式的內部不能呼叫非靜態方法,反過來可以。可以僅僅通過類本身呼叫static成員函式。

9 垃圾回收器只知道釋放那些經由new分配的記憶體,而無法釋放非new建立的特殊記憶體區域。Java允許在類中定義一個名為finalize()的方法來應對這種情況。

原理:一旦垃圾回收器準備好釋放物件佔用的儲存空間,將首先呼叫其finalize()方法,並且在下一次垃圾回收動作發生時才會真正回收物件佔用的記憶體。

10 java裡的物件卻並非總是被垃圾回收。即物件可能不被垃圾回收。垃圾回收並不等於“析構”,垃圾回收只與記憶體有關。

11 java沒有delete操作符,也沒有解構函式

12 java不允許建立區域性物件,必須使用new建立物件。

13 對於函式的區域性變數如果沒有初始化,java會報錯。對於類的成員變數,如果是基本型別都會有一個預設初始值。

public class HelloDate {
	boolean t;
	char c;
	byte b;
	short s;
	int i;
	long l;
	float f;
	double d;
	HelloDate reference;
	void printIntialValues(){
		System.out.println("Data type Initial value");
		System.out.println("boolean: "+t);
		System.out.println("char: "+c);
		System.out.println("byte: "+b);
		System.out.println("short: "+s);
		System.out.println("int: "+i);
		System.out.println("long: "+l);
		System.out.println("float: "+f);
		System.out.println("double: "+d);
		System.out.println("HelloDate: "+reference);
	}
	public static void main(String[] args){
		HelloDate d = new HelloDate();
		d.printIntialValues();
	}
}

輸出如下,boolean預設值為false,char,byte,short,int,float,long,double都是0,引用為null

Data type Initial value

boolean: false

char: 

byte: 0

short: 0

int: 0

long: 0

float: 0.0

double: 0.0

HelloDate: null

14 類的成員變數指定初始化

public class HelloDate {
	boolean t = true;
	char c = 'x';
	byte b = 45;
	short s = 0xff;
	int i = 99;
	long l = 12;
	float f = 3.12f;
	double d = 31.455;
	HelloDate reference;
}

15 也可以通過呼叫成員函式給成員變數提供初值

// 第一種型別
public class HelloDate {	
	int i = f();
	int f(){
		return 12;
	}
}


// 第二種型別,一定要注意順序,i要先被賦值才能給j的賦值操作做引數
public class HelloDate {	
	int i = f();
    int j = g(i);
	int f(){
		return 12;
	}
    int g(int i){
        return i*10;
    }
}

16 在類的內部,變數定義的先後順序決定了初始化的順序。即使變數定義散佈於方法之間,它們仍舊會在任何方法(包括構造器)被呼叫之前得到初始化。

class Window{
	Window(int marker){ System.out.println("Window("+marker+")");}
}

public class HelloDate {
	Window w1 = new Window(1);
	HelloDate(){
		System.out.println("HelloDate");
		w3 = new Window(33);
	}
	Window w2 = new Window(2);
	void f(){ System.out.println("f()");}
	Window w3 = new Window(3);
	public static void main(String[] args){
		HelloDate d = new HelloDate();
		d.f();
	}
}

17 無論建立多少個物件,靜態資料都佔用一份儲存區域static關鍵字不能應用於區域性變數,只能作用於成員變數

class Bowl{
	Bowl(int marker){
		System.out.println("Bowl("+marker+")");
	}
	void f1(int marker){
		System.out.println("f1("+marker+")");
	}
}
class Table{
	static Bowl bowl1 = new Bowl(1);
	Table(){
		System.out.println("Table()");
		bowl2.f1(1);
	}
	void f2(int marker){
		System.out.println("f2("+marker+")");
	}
	static Bowl bowl2 = new Bowl(2);
}

class Cupboard{
	Bowl bowl3 = new Bowl(3);
	static Bowl bowl4 = new Bowl(4);
	Cupboard(){
		System.out.println("Cupboard()");
		bowl4.f1(2);
	}
	void f3(int marker){
		System.out.println("f3("+marker+")");
	}
	static Bowl bowl5 = new Bowl(5);
}

public class HelloDate {
	
	public static void main(String[] args){
		System.out.println("Creating new Cupboard() in main");
		new Cupboard();
		System.out.println("Creating new Cupboard() in main");
		new Cupboard();
		table.f2(1);
		cupboard.f3(1);
	}
	static Table table = new Table();
	static Cupboard cupboard = new Cupboard();
}

// 輸出
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)

類初始化的順序是先靜態變數,而後是非靜態變數,再構造器。靜態變數只會被初始化一次

18 物件的建立過程,假設有個名為Dog的類

  1. 即使沒有顯式地使用static關鍵字,構造器實際上也是靜態方法。因此,當售出建立型別為Dog的物件時,或者Dog的靜態方法/靜態變數首次被訪問時,java直譯器必須查詢類路徑,以定位Dog.class檔案
  2. 然後載入Dog.class,有關靜態初始化的所有動作都會執行。因此靜態初始化只在Class物件首次載入時進行一次
  3. 當new Dog()建立物件時,首先將在堆上為Dog物件分配足夠的儲存空間
  4. 這塊儲存空間會被清零,自動地將Dog物件中的所有基本型別資料都設定為預設值,而引用設定為null
  5. 執行所有出現於欄位定義處的初始化動作
  6. 執行構造器

19 Java允許將多個靜態初始化工作組織成一個靜態塊,如下

class Cup{
	Cup(int marker){
		System.out.println("Cup("+marker+")");
	}
	void f(int marker){
		System.out.println("f("+marker+")");
	}
}
class Cups{
	static Cup cup1;
	static Cup cup2;
	static {
		cup1 = new Cup(1);
		cup2 = new Cup(2);
	}
	Cups(){
		System.out.println("Cups()");
	}
}

public class HelloDate {
	
	public static void main(String[] args){
		System.out.println("Inside main()");
		Cups.cup1.f(99);
	}

}

//輸出
Inside main()
Cup(1)
Cup(2)
f(99)

20 非靜態的程式碼塊

class Cup{
	Cup(int marker){
		System.out.println("Cup("+marker+")");
	}
	void f(int marker){
		System.out.println("f("+marker+")");
	}
}
class Cups{
	Cup cup1;
	Cup cup2;
	{
		cup1 = new Cup(1);
		cup2 = new Cup(2);
		System.out.println("cup1 & cup2");
	}
	Cups(){
		System.out.println("Cups()");
	}
	Cups(int marker){
		System.out.println("Cups("+marker+")");
	}
}

public class HelloDate {
	
	public static void main(String[] args){
		System.out.println("Inside main()");
		new Cups();
		System.out.println("new Cups() completed");
		new Cups(2);
		System.out.println("new Cups(2) completed");
		
	}
}

//輸出
Inside main()
Cup(1)
Cup(2)
cup1 & cup2
Cups()
new Cups() completed
Cup(1)
Cup(2)
cup1 & cup2
Cups(2)
new Cups(2) completed

21 陣列定義,有兩種方式,定義時編譯器不允許指定陣列大小。陣列定義只是擁有了對陣列的一個引用,還沒有給陣列物件本身分配任何空間。初始化時會給陣列建立相應的儲存空間。

int[] a1   // ok
int a2[]   // ok


int[4] a3   // error,不能指定陣列大小
int a4[5]   // error,不能指定陣列大小

22 陣列的初始化

int[] a1 = {1,2,3,4,5};

int[] a2;
a2 = a1;

int[] a3 = new int[4];

23 陣列都有一個固定成員,length,表示陣列個數。陣列越界,java會報錯。但C/C++不會報錯。陣列的大小可以在執行時確定

int[] a;
Random r = new Random(45);
a = new int[r.nextInt(20)];
System.out.println("length of a = "+a.length);  // 檢視個數
System.out.println(Arrays.toString(a));         // 檢視陣列內容

24 如果定義一個非基本型別的陣列,那麼只是建立了一個引用陣列,並且直到通過建立新的Integer物件,並把物件賦值給引用,初始化才算結束。

// 第一種類陣列初始化         
Integer[] b1 = {
    new Integer(1),
    new Integer(2),
    3
};

// 第二種類陣列初始化
Integer[] b2 = new Integer[]{
    new Integer(3),
    new Integer(4),
    3,                  // 最後這個逗號可選
};
		
Random rand = new Random(47);

// 第三種類陣列初始化
Integer[] a = new Integer[rand.nextInt(20)];
for(int i=0;i<a.length;i++)
    a[i] = rand.nextInt(500);
System.out.println("length of a = " + a.length);
System.out.println(Arrays.toString(a));

25 int k[] = {1,2,3 , }; 最後的一個逗號是可選項,可以沒有也可以有

26 可以建立以Object陣列為引數的函式,如下

class A{}

public class HelloDate {
	
	static void printArray(Object[] args){
		for(Object obj:args)
			System.out.print(obj+" ");
		System.out.println();
	}
	
	public static void main(String[] args){
		
		printArray(new Object[]{   // 不同型別變數組成的陣列
				new Integer(47),new Float(4.13),new Double(4.333)
		});
		printArray(new Object[]{"one","two","three"});
		printArray(new Object[]{new A(),new A(),new A()});
	}

}

//輸出
47 4.13 4.333 
one two three 
[email protected] [email protected] [email protected] 

27 在Java SE5中,加入了可變的引數列表,即資料型別,後面緊跟著省略號,即 function( T . . .  args ) ,省略號必須是三點,

T可以使用任何型別的引數,包括基本型別。

static void printArray(Object... args){  // 可變引數列表
	for(Object obj:args)
		System.out.print(obj+" ");
	System.out.println();
}

public static void main(String[] args){
	
	printArray(34,34.1f,12.333);   // 可以同時傳多個引數
	printArray(new Integer(4),new Float(3.423),new Double(11.1));
	printArray(new A(),new A(),new A());
	printArray("one","two","ok");
	printArray(new Integer[]{1,2,3});
	printArray((Object[])new Integer[]{1,2,3});   // 可以傳陣列
	printArray();    // 可以是空的引數
}
static void f(int required,String... args){  // 可變引數列表
	System.out.print("required: "+required+" ");
	for(String s:args)
		System.out.print(s+" ");
	System.out.println();
}

public static void main(String[] args){
	
	f(1,"one");
	f(2,"two","three");
	f(0);
}
static void f(Character... args){  // 可變引數列表
	System.out.print(args.getClass());
	System.out.println("length: "+args.length);
}

static void g(int... args){  // 可變引數列表,資料型別可以是基本型別
	System.out.print(args.getClass());
	System.out.println("length: "+args.length);
}


public static void main(String[] args){
	
	f('a');
	f();
	g(1);
	g();
	System.out.println("int[]: "+new int[0].getClass());
}

//輸出
class [Ljava.lang.Character;length: 1
class [Ljava.lang.Character;length: 0
class [Ilength: 1
class [Ilength: 0
int[]: class [I     // [ 表示陣列,I表示基本型別int

函式有了可變引數,編譯器會為其自動填充陣列,這個引數在函式內就是一個數組型別。

28 在Java SE5添加了enum關鍵字,由於列舉型別的例項是常量,所以它的具名值都是大寫字母表示。

public enum Spiciness{
	NOT,MILD,MEDIUM,HOT,FLAMING
}
public static void main(String[] args){
	Spiciness howHOT = Spiciness.MEDIUM;
	System.out.println(howHOT);      // 輸出MEDIUM

    for(Spiciness s : Spiciness.values())
	    System.out.println(s+" , ordinal "+s.ordinal());
}

輸出:
MEDIUM
NOT , ordinal 0
MILD , ordinal 1
MEDIUM , ordinal 2
HOT , ordinal 3
FLAMING , ordinal 4

在建立enum時,編譯器會自動給新增一些特性,比如新增toString(),ordinal()和values()等函式