顯示具有 Java 標籤的文章。 顯示所有文章
顯示具有 Java 標籤的文章。 顯示所有文章

2012年5月27日

Java 取得網頁資料

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;

public class HttpGetURL {


    public String str = "";
    public int line = 0;

    //public java.net.URL u;
    String url;
    String method;
    String code;
    
    public String allURL = "";
    
    public HttpGetURL() {}
    
    public void setURL(String url) {
        this.url = url;
        this.method = "GET";
        this.code = "";
        this.line = 0;
        this.allURL = url + "&" + Math.random();
        //HttpGetURL h = new HttpGetURL(url , "" , "GET");
        //str = h.str;
        //line = h.line;
    }

    public void setURL(String url, String code, String RequestMethod) {
        this.url = url;
        this.code = code;
        this.line = 0;
        this.method = RequestMethod;
        this.allURL = url + "?" + code + "&" + Math.random();
    }

    public void connect() {
        //StringBuffer s = new StringBuffer();
        String s = "";
        try {
            java.net.URL u = new java.net.URL(allURL);
            java.net.HttpURLConnection http = (java.net.HttpURLConnection) u.openConnection();

            http.setRequestMethod(method);
            //System.out.println(http.getRequestMethod());

            int n =  http.getResponseCode();

            //System.out.println(u.toString());
            //System.out.println(n + " " + HttpURLConnection.HTTP_OK);
            if (n == HttpURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        http.getInputStream(), "utf-8"));
                String tmp = null;

                while ((tmp = br.readLine()) != null) {
                    //s.append(tmp);
                    s += tmp;
                    line++;
                }

                str = s.toString();
            } else
                str = "Error";
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
            //StackTraceElement[] em = ex.getStackTrace();
            str = "Error";
        }
        //s.delete(0, s.length());
    }
}
public class MAIN {
 public static void main(String[] args){
  HttpGetURL link = new HttpGetURL();
  
  String url = "http://www.google.com/";
  String code = "a=1";
  String RequestMethod = "GET";
  
  link.setURL(url, code, RequestMethod);
  link.connect();
  System.out.println(link.allURL);
  System.out.println(link.str);
 }
}

2012年3月25日

等腰三角

    public static void main(String[] args) {
        int w = 10;//底邊長
        //case 0 : 無恥數學解
        for(int x = 0 ; x < w/2+1 ; x++){
            for(int y = 0 ; y < w ; y++){
                if(x-y+(w/2) == 0 || x+y-(w/2) == 0 || x == w/2+1-1)
                    System.out.print("* ");
                else 
                    System.out.print("- ");
            }
            //如果 底邊 長度是偶數 則要補一個* 不然會缺一角
            if(x == w/2+1-1 && w%2 == 0)
                System.out.print("* ");
            System.out.println();
        }
        
        System.out.println();
        //case 1 : 苦命解
        for(int x = 0 , cont = w/2 ; x < w/2+1 ; x++ , cont--){
            //印出每行前面的空白
            for(int y = 0 ; y < cont ; y++){
                System.out.print("- ");
            }
            //印出第一個*
            System.out.print("* ");
            //印出空心部分的空白
            if(x != w/2+1-1){
                for(int y = 0 ; y < ((w/2)-cont-1)*2+1 ; y++){
                    System.out.print("- ");
                    //最後印出第二個*
                    if(y == ((w/2)-cont-1)*2+1-1)
                        System.out.print("* ");
                }
            }else if(x == w/2+1-1){//如果到了最後一行則印出整行*
                for(int y = 0 ; y < w-1 ; y++){
                    System.out.print("* ");
                }
                //如果 底邊 長度是偶數 則要補一個* 不然會缺一角
                if(w%2 == 0)
                    System.out.print("* ");
            }
            System.out.println();
        }
    }

}

2011年8月2日

UVa - p100

p100 問題連結

import java.io.BufferedInputStream;
import java.util.Scanner;

public class u100 {
	int max;
	int min;
	int cont;
	public u100(){
		Scanner sc = new Scanner(new BufferedInputStream(System.in));
		String s;
		while(sc.hasNext()){
			int a = sc.nextInt();
			int b = sc.nextInt();
			if(a > b){
				max = a;
				min = b;
			}else{
				max = b;
				min = a;
			}
			int contmax = 0;
			for(; min <= max ; min++){
				cont = 0;
				f(min,max);
				if(contmax < cont)
					contmax = cont;
			}
			System.out.println(a + " " + b + " " + contmax);
		}
	}
	
	public void f(int n , int j){
		//System.out.print(n + " ");
		cont++;
		if(n == 1){
			//stop
		}else{
			if(n%2==1){
				n = 3*n+1;
			}else{
				n = n/2;
			}
			f(n,j);
		}
	}
	
	public static void main(String[] args){
		new u100();
	}
}

2011年2月28日

遞迴練習 河內塔

public class tower {
	
	void tower(int n , String a , String b , String c){
		if(n == 1){
			System.out.println(a + " to " + c);
		}else{
			tower(n-1 , a , c , b);
			tower(1 , a , b , c );
			tower(n-1 , b , a , c);
		}
	}
	
	public static void main(String[] args) {
		tower t = new tower();
		t.tower(3, "B" , "C" , "A");
	}
}

遞迴練習 三角形

public class tri {
	/*
	Enter n = 5
	tri1
	*
	**
	***
	****
	*****
	tri2
	*****
	****
	***
	**
	*
	tri3
	    *
	   **
	  ***
	 ****
	*****
	tri4
	*****
	 ****
	  ***
	   **
	    * 
	*/
	public void prchar(String c , int n){
		for(int i = 0 ; i < n ; i++)
			System.out.print(c);
	}
	
	public void tri1(int n){
		if(n == 1){
			prchar("*",1);
			System.out.println();
		}else{
			tri1(n-1);
			prchar("*",n);
			System.out.println();
		}
	}
	
	public void tri2(int n){
		if(n == 1){
			prchar("*",1);
			System.out.println();
		}else{
			prchar("*",n);
			System.out.println();
			tri2(n-1);
		}
	}
	
	public void tri3(int n , int m){
		if(n == 1){
			prchar(" ",m-1);
			prchar("*",1);
			System.out.println();
		}else{
			tri3(n-1 , m);
			prchar(" ",m-n);
			prchar("*",n);
			System.out.println();
		}
	}
	
	public void tri4(int n , int m){
		if(n == 1){
			prchar(" ",m-1);
			prchar("*",1);
			System.out.println();
		}else{
			prchar(" ",m-n);
			prchar("*",n);
			System.out.println();
			tri4(n-1 , m);
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		java.util.Scanner sc = new java.util.Scanner(System.in);
		int n;
		System.out.print("Enter n = ");
		n = sc.nextInt();
		
		tri t = new tri();

		System.out.println("tri1");
		t.tri1(n);
		System.out.println("tri2");
		t.tri2(n);
		System.out.println("tri3");
		t.tri3(n, n);
		System.out.println("tri4");
		t.tri4(n, n);
		
	}
}

2010年6月23日

關於 Abstract and Interface 三兩事

Abstract Class 和 Interface 本身都無法用來建構一個 object (物件實體) ,它們必須透過其他類別以 extends (繼承) 或 implements (實作) 來完成目的

  • Abstract
    • 當整個類別繼承體系有一致的行為時,我們通常會將這些行為抽離到上一層的 super class 去。如果這些行為的程式碼不在 super class 中定義的話,那麼會使得其 sub class 必須重覆地出現相同的程式片段,導致了壞味道的發生。然而有時我們並不打算讓這些 super class 可以被建構成物件實體,那麼它們就是所謂的 Abstract Class 。
  • Interface
    • 在我們確定了物件之間的溝通方式及規格,卻未能確定其實作細節時,就是利用 Interface 的時機。 Interface 能保證 Client 在操作物件上有一致的方式,而具體的表現方式則是讓實作的類別來決定。因此這些類別都必須實作在 Interface 裡定義的 method ,否則將會出現錯誤。在 Interface 中所有方法都是 abstract 的,定義方式和 Abstract Class 的抽象方法一樣,但是不用加上 abstract 關鍵字

兩者的使用時機

  1. 當類別有共同的行為或屬性時,可以考慮使用 Abstract Class。
  2. 類別有共同的操作介面,但是實作上卻有所差異時,可以考慮使用 Interface。

2009年11月15日

JDBC 連結 MySQL

mysql-connector-java-5.1.8.tar.gz
http://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.8.tar.gz/from/pick#mirrors
須把 mysql-connector-java-5.1.8-bin.jar
放到 Tomcat 5.5\shared\lib

2009年9月18日

object-oriented

OO
Java 是物件導向的(object-oriented)語言。物件導向近年來成為顯學,全新的程式語言幾乎都具備物件導向的特色,而舊的程式語言也紛紛在新版本中開始支援物件導向的特色。
所謂「物件導向的特色」,指的是物件導向的三個機制,三者缺一不可,此三個機制分別為封裝(encapsulation)、繼承(inheritance)、多型(polymorphism)。我也喜歡把這三個機制稱為三個階段,以突顯出它們之間的次序性:沒有封裝就不可能會有繼承,沒有繼承就不可能會有多型。為了稱呼上的方便,我們常常將物件導向簡稱為 OO。
有一些程式語言常被誤認為是 OO 的語言,但其實不然。例如:Visual Basic 6 以及更早的版本只支援封裝,不支援繼承和多型,所以不可以被視為 OO 的語言。這種只支援封裝 的語言,只能被稱為 object-based 程式語言。但是 Visual Basic 7(也就是 Visual Basic.NET)開始支援繼承和多型,所以可以被視為 OO 的語言,因此威力大增,語言的複雜度也會大增,因為繼承和多型會帶來許多複雜的特質。
1.封裝(encapsulation)
關於封裝,你可以扮演兩種角色:
    • 封裝者:封裝出一個類別(class),以供他人使用。
    • 類別使用者:使用別人封裝出來的類別
程式員都是在這兩種角色之間不斷地轉換:一會兒封裝出一個類別,一會兒使用別人封裝好的類別。當一個類別使用者顯然比當一個封裝者簡單許多,只要透過 new 這個關鍵字來產生類別的 instance,即可使用。如果欲使用的是 class method/field,甚至連 new 都可以省了。既然當類別使用者比當封裝者來得簡單,我們自然是盡量使用既有的類別, 這樣就可以達到很高的再用性(reusability)。Java 平台提供了數千個已經封裝好的類別,我們可以直接拿來使用,這可以為我們省下許多時間。這些類別所形成的集合,就稱為 API。
查詢 Java API
J2SE 平台所具備的 API,就稱為 Core API(核心 API)。你可以在你的 Java 2 SDK 路徑下找到 docs/api/index.html,這就是 API 文件,從這裡,你就可以找到每個類別的用法(例如我們在 Hello 程式中使用的 System,就是一個類別)。畫面如下所示:
clip_image002[6]
我很喜歡把程式設計比喻成設計一個主機板。主機板的設計者不用一切從頭來,因為他們有許多 IC chip(晶片)可以使用(其中有一個 chip 為 CPU)。從市面上的各種 chip 中(SIS、Intel、VIA…),挑選出各種適合的 chip,再把這些 chip 全都放到主機板上適當的位置固定好,再把這些 chip 的接腳之間互相 連接起來就可以了。這麼一來,設計主機板的工作包含:
    1. 挑選 chip
    2. 應用這些 chip 來進行電路佈局(circuit layout)
寫程式很類似設計主機板,差異在於主機板是硬件,程式是軟件。寫 Java 程式不用一切從頭來,因為我們有許多類別可以使用。從 Java Core API 的類別中, 挑選出各種你需要的類別,把這些類別用在你的程式中,程式中利用 Java 的關鍵字(keyword) 和算符(operator)將這些類別銜接起來就可以了。這麼一來,寫程式的工作包含:
    1. 挑選適當的類別
    2. 應用這些類別來完成程式




2.繼承(inheritance)
既有的 Java API 已經可以滿足我們大多數時候的需求,但還是有些時候,我們希望有一個類別能提供特定的功能,但是 Java API 不提供這樣的類別。我們通常會找協力廠商(thirty party)購買這樣的類別。有許多軟體公司專門提供類別庫(class library),收納了許多好用的類別,例如繪製統計圖表(chart)的類別、產生報表(report)的類別、複雜科學計算的類別……等。你可以在 WWW 上找到許多這樣的產品。
如果沒有任何廠商提供完全符合你需求的類別,或者你根本不想增加成本購買 third party 的類別(這些類別通常都不單獨出售, 而是許多類別被包在一起成為類別庫,且售價不便宜),那麼你只好自己寫一個這樣的類別。
假設我們現在就有這樣的需求,需要設計一個類別。在下面的程式碼中,我們封裝出一個名為 ClassB 類別:
// code-1
class ClassB
{
     int doThis() {
               // ...
               // ...很多、很多程式碼...
               // ...
     }
     int doThat() {
                // ...
                // ...很多、很多程式碼...
                // ...
     }
}
這時候,你發現有一個叫做 ClassA 的類別,也提供了 doThis() 和 doThat(),其中 ClassA 的 doThis() 完全就是 ClassB 的 doThis() 所需要的功能,但是 ClassA 的 doThat() 卻和 ClassB 的 doThat() 所需要的功能有一些小差異,你希望 ClassB 的 doThat() 傳出值一定是大於等於零的整數。 你可以把 ClassA 拿來運用在 ClassB 中,將 code-1程式改寫如下:
// code-2
class ClassB {
        ClassA a = new ClassA();
        int doThis() {
             return a.doThis();
        }
        int doThat() {
                return Math.abs(a.doThat());
                // Math.abs() 是取絕對值(正數)的意思 
        }
}
code-2 的版本因為運用 ClassA,所以整個程式比 code-1 更精簡。我們稱 ClassA 被嵌入(embed)到 ClassB 中ClassB 把 method 遞送給 ClassA 的 method 來處理。
如果 ClassA 除了具有 doThis() 和 doThat() 之外,還具有100 個 method, 分別叫做 method1() method2()、……、method100(),而且這100 個 method 每個都是 ClassB 想要具備的功能,那麼我們的 code-2 程式可以改寫如下:
// code-3
class ClassB {
        ClassA a = new ClassA();
        int doThis() {
                return a.doThis();
        }
        int doThat() {
                return Math.abs(a.doThat());
        }
        int method1() {
                return a.method1();
        }
        int method2() {
                return a.method2();
        }
        // ...一直重複類似的程式碼
        
        int method100() {
               return a.method100();
        }
}
這根本就是一場惡夢, 因為我們不斷地把 ClassB 的 methodX() 轉給 ClassA 的 methodX()。這個程式糟透了, 我們應該把它改成下面的版本:
// code-4
class ClassB extends ClassA{ //ClassB 繼承 ClassA
        int doThat() {
                return Math.abs(a.doThat());
        }
}
code-4 的版本用到繼承(inheritance)的技巧。繼承也是封裝的一種,所以語法和封裝很類似,唯一的差異是多了 extends 以及後面的 ClassA。extends 是 Java 的關鍵字,後面接著一個類別的名稱,用來表示繼承的來源。以此例來說,我們稱 ClassA 是 ClassB 的父類別(parent class),或超類別(super class),或基底類別(base class)我們稱 ClassB 是 ClassA 的子類別(child class),或次類別(sub-class),或衍生類別(derived class)。
code-4 的寫法之所以比 code-3 簡潔,是因為 code-4 使用繼承。在 code-4 中,雖然 ClassB 本身只定義了一個 method,也就是 doThat() ,但是 ClassA 中的 method 也會被自動繼承過來。 換句話說,我們可以拿 ClassB 的對象來呼叫 ClassA 中定義的 method,如下例所示:
ClassB b = new ClassB();

b.doThis();

b.method1();
這就是繼承的目的「之一」:達到程式碼的再用性(reusability)。ClassB 輕易地運用了 ClassA 的程式碼。(繼承的另一個目的是:為多型做準備。)我主張繼承應該被視為一種特殊的封裝,因為繼承只是一種「過程」,繼承的結果仍是封裝,一個全新的封裝。
在繼承的時候,如果子類別定義了和父類別完全相同名稱(包括參數、傳出值、修飾字)的 method,我們就說子類別的此 method 推翻(override)了父類別的同名 method。從 code-4 的例子來看,ClassB 的 doThat() 推翻了 ClassA 的 doThat()。
請注意,在繼承的時候,不只 instance method 會被繼承,連 instance field、class field、class method 都會被繼承。
如果你不希望你所設計出來的類別被其他類別繼承,那麼你可以利用 final 來修飾此 class,如下所示:
// code-5
final class MyClass {
        // ...
}
如果你不希望你所設計出來的某個 method 被子類別推翻(override),那麼你可以利用 final 來修飾此 method,如下所示:
// code-6
class MyClass {
        final int myMethod() {
                // ...
        }
}
java.lang.Object
在 Java 中,每個類別都會有父類別。如果你沒有用 extends 關鍵字來指定父類別,那麼它的父類別就是 java.lang.Object, 例如:code-6 的程式其實等同於下面的程式:
// code-7
class MyClass extends java.lang.Object {
        final int myMethod() {
                // ...
        }
}
java.lang.Object 是一個很特殊的類別,因為:
    • 它是唯一沒有父類別的類別
    • Java 所有的類別都直接或間接地繼承了 java.lang.Object
請牢記下面三點:
    1. 每個類別(java.lang.Object 除外)一定有一個父類別
    2. 一個父類別可以有許多子類別
    3. 所有的類別都源自於 java.lang.Object
繼承的使用時機
認清繼承的使用時機很重要。如果存在某個類別(比方說 ClassA), 其功能和我們的需求「差不多」,但有一些不同之處,那麼我們就「可以」 使用繼承的方式來設計一個類別(比方說 ClassB),以將 Class 的功能抄襲過來, 並進行「擴充」或「修改」。
「可以」使用繼承,不代表「一定要」使用繼承。 繼承也不見得全然都只有好處,沒有任何缺點。有些時候,兩個 class 之間的關係,用 association 的關係比用繼承的關係好。也就是說,有些時候我們不用 code-4 的版本,反而使用 code-2 的版本,因為這樣做有下列的好處:
  • 在 code-2 中,a 可以被其他類使用;但在 code-4 中,則無法這麼做。
  • 在 code-2 中,a 可以隨時被設定成別的物件;但在 code-4 中,則無法改變。
  • ClassB 可以不提供部份的 method,例如:code-2 就不提供 method1()~method100();
    但在 code-4 中, ClassB 無法決定哪些 method/field 要繼承或不繼承。
特別注意:繼承一定需要「擴充」或「修改」,如果不擴充也不修改,這樣的繼承就毫無意義可言所謂的擴充,指的是:子類別新定義父類別沒有的 method,以擴充功能;所謂的修改,指的是子類別提供 method 推翻父類別的同名 method。
3.多型(polymorphism)
關於多型(Polymorphism),一言以蔽之:「當某變數的實際型態(actual type)和形式型態(formal type)不一致時,呼叫此變數的 method,一定會呼叫到「正確」的版本, 也就是實際型態的版本。」
從這句話,我們可以思索下面的問題:
    1. 為什麼實際型態和形式型態會不一致?
    2. 多型帶來時麼好處?
如果你能夠瞭解這兩點,你就能徹底瞭解多型。
學會多型之後,你不可以對多型有「錯誤的期待」。千萬要小心下面這兩點:
    1. 多型的機制只用在 method 上,不用在 field 上。
    2. 多型的機制只用在 instance method上,不用在 class method 上。
在本文章中,我也會對上述兩點提出明確的解釋。
為什麼實際型態和形式型態會不一致?
請看下面的例子:
int a = 3;

long b = a;
因為 a 和 b 是基本型態(primitive type),而非 reference 型態,所以 a 的值會被複製一份到 b。在複製的過程中,a 的值原本是 32 bit 的 int,會被自動地擴充成(widen)64 bit 的 long,再指定(assign)給 b。正因為有擴充和複製,所以對於 b 來說,其實際型態(值的型態)和形式型態(宣告時的型態)都一樣是 long。
所有屬於基本型態的變數都類似如此,在設定其值的時候,會經歷擴充(或縮減)以及複製,製造出實際型態和形式型態一致的值。
但是 reference 型態可就不一樣了。請看下面的例子:
class ClassA {
    void method1() {
        System.out.println("method1() in ClassA");
    }
    void method2() {
        System.out.println("method2() in ClassA");
    }
}
class ClassB extends ClassA {
    void method1() {
        System.out.println("method1() in ClassB");
    }
    void method3() {
        System.out.println("method3() in ClassB");
    }
}
public class ClassC {
    public static void main(String[] args) {
        ClassA a = new ClassB();
        a.method1();    // method1() in ClassB
        a.method2();    // method2() in ClassA
        a.method3();    // compile-time error
    }
}
對於 reference 型態來說,使用指定算符(assignment operator)時, 只有記憶體位址會被複製,對象本身不會被複製,所以實際值並不會受到變寬或變窄的破壞。
我們在 ClassC 中,產生一個 ClassB 的對象,並將它設定給 a。但是 a 被宣告成 ClassA 型態,所以 a 的實際型態(ClassB)和形式型態(ClassA)並不一致。 在這樣的情況下,呼叫 a 的 method1() 會執行到哪一個版本?實際型態的版本或形式型態的版本?正確答案是實際型態(ClassB)的版本。這就是多型!
讓我們再看一次文章一開始對多型所下的定義:「當某變數的實際型態和形式型態不一致時,呼叫此變數的 method,一定會呼叫到正確的版本,也就是實際型態的版本」。現在,你是不是比較能體會了。
如果我們嘗試著呼叫 a 的 method2() 時,結果會呼叫到 ClassA 的 method2(),這是因為 ClassB 沒有定義 method2(),其 method2() 乃是繼承 ClassA 而來的。
如果我們嘗試著呼叫 a 的 method3() 時,則無法通過編譯。 這是因為 Java 是強制型態檢查的語言(strongly-typed language),這意味著 編譯時會檢查形式型態是否有提供該 method。a 的形式型態是 ClassA,不提供 method3(),雖然 a 的實際型態有提供 method3(),但編譯只管形式型態, 可不管實際型態,所以形式型態也稱為編譯期型態(compile-time type), 實際型態也稱為執行期型態(runtime type)。
或許你會覺得「ClassA a = new ClassB();」的寫法很怪,為什麼要把 ClassB 的物件宣告成 ClassA 型態?的確,通常我們不會這麼做,但形式型態和實際型態互異的情況卻往往是在不知不覺中發生,請看下面的例子:
class ClassA {
    void method1() {
        System.out.println("method1() in ClassA");
    }
    void method2() {
        System.out.println("method2() in ClassA");
    }
}
class ClassB extends ClassA {
    void method1() {
        System.out.println("method1() in ClassB");
    }
    void method3() {
        System.out.println("method3() in ClassB");
    }
}
class ClassD {
    static void method4(ClassA a) {
        // a 的形式型態是 ClassA,實際型態則不一定是 ClassA
        a.method1(); //呼叫實際型態的 method1();
    }
}
public classE {
    public static void main(String[] args) {
        ClassB b = new ClassB();
        ClassD.method4(b);
        // ClassD.method4() 需要一個 ClassA的參數,
        // 因為 ClassB 繼承自 ClassA,
        // 所以 ClassB 相容於 ClassA,
        // 因此我們可以傳入 ClassB 的對象當參數
    }
}
因為我們傳進 ClassD.method4() 的參數其實際型態是 ClassB,但是在 method4() 的定義中將它宣告為 ClassA,造成了形式型態和實際型態不一致。這類似於「ClassA a = new ClassB();」的寫法,只不過一切都是在暗中進行,從程式上來看並不明顯。大部分的多型,都是導因於此。
從上面的例子來加以歸納,我們可以知道多型的發生必須是:
    1. 有直接或間接繼承關係的兩個類別,子類別的 method 將父類別的 method 予以override。
    2. 實際型態為子類別的物件,被當成父類別來使用,呼叫其 overrided method。
多型帶來什麼好處?
多型是建立在繼承的基礎之上的,沒有繼承,就不會有多型繼承的目的有兩種
    • 繼承程式碼:達到程式碼再用性(reuse)
    • 繼承介面(interface)。達到介面再用性(reuse),為多型預作準備
更明白地說:多型是仰賴介面的繼承。至於程式碼的繼承,完全無涉於多型。
讓我打個比喻:電腦主機板(Main Board)上面能夠插上 Intel 的 CPU,也能插上 AMD 的 CPU,一切運作順利,那是因為 Intel 的 CPU 和 AMD 的 CPU 都遵守該主機板要求的介面(interface)。 這麼一來,任何廠商只要能符合此介面,就能和該主機板搭配使用,主機板不需要做出任何修改。
同樣地,ClassD 的 method4() 需要 ClassA 的介面,不管是 ClassA 的 instance 和 ClassB 的 instance 都能符合這樣的要求(ClassB 繼承了 ClassA 的介面), 所以都能當作 method4() 的參數,和 ClassD.method4() 合作無間。任何對象只要能符合 ClassA 的介面,就能和 ClassD 合作無間,ClassD 的程式碼不需要進行任何修改。 多型的機制,讓程式具備了動態的擴充性。
Reflection 也可以讓程式具備動態的擴充性,甚至比多型更動態,所以有些場合可以使用 reflection 來取代多型,但 reflection 通常效率較差,而且有的語言不提供 Reflection 機制。 Java 早在 1.1 以後就開始支援 Reflection API 了 ,而 Java1.4 版的 Reflection API 速度也大幅地提升了。如果你對於 Java Reflection API 感興趣的話,可以參考 java.lang.reflect.*。
多型的機制只用在 method 上,不用在 field 上
簡單來說,只要符合下兩點,就可能會有多型:

    1. 有直接或間接繼承關係的兩個類別,子類別的 method 將父類別的 method 予以 override。
    2. 實際型態為子類別的對象,被當成父類別來使用,呼叫其 overrided method。
請注意:上述兩點指的是 method,而非 field。對於 field 來說,根本沒有多型這一回事。請看下面的例子:
class ClassA {
    String field1 = 'A1';
    String field2 = 'A2';
}

class ClassB extends ClassA {
    String field1 = 'B1';
    String field3 = 'B3';
}

public class ClassC {
    public static void main(String[] args) {
        ClassA a = new ClassB();
        System.out.println(a.field1());    // "A1"
        System.out.println(a.field2());    // "A2"
        System.out.println(a.field3());    // compile-time error
    }
}
對於 field 來說,形式型態決定了一切,完全和實際型態無關。 雖然 a 的實際型態是 ClassB,但是形式型態是 ClassA,所以 a.field1 得到的結果是”A1”,a.field2 得到的結果是”A2”
如果子類別提供了和父類別一樣名稱與參數的 method, 我們說子類別的 method 把父類別的同名 method 給 override 了。如果子類 別提供了和父類別一樣名稱的 field,我們說子類別的 field 把父類別的同名 field 給 shadow 了。
針對 method 和 field 的作法居然如此大的不同,這絕對不是 Java 語言的設計者故意想折磨你。事實上,這樣的設計有其巧妙之處。在 Java 的思維中:介面是對象之間溝通的管道,而介面只包含了類別的名稱和 method 的集合。至於 field,則是不屬於介面的一部份既然如此,而多型又是完全是 依靠介面,所以當然多型會把 field 排除在外。
多型的機制只用在 instance method 上,不用在 class method 上
被 static 修飾的 field/method 是屬於 class field/method。繼承的時候,依然可以繼承這些 static field/method。封裝和繼承的效果可以同時用在 class 或 instance 上。換句話說:封裝不只封裝 instance field/method,也可以封裝 class field/method;繼承不只繼承父類的 instance field/method,也繼承父類別的 class field/method。
但是,切記,多型只能對 instance 產生作用,不能對 class 產生作用,這可以從我對多型的定義看出端倪,定義如下:
當某變數的實際型態和形式型態不一致時,呼叫(invoke)此變數的 method,一定會呼叫到正確的版本,也就是實際型態的版本。
class 是形式型態,沒有實際型態,根本就和多型無關只有 instance 才可能會造成形式型態和實際型態不一致。
請看下面的例子:
class ClassA {
    static void method1() {
        System.out.println("method1() in ClassA");
    }
    static void method2() {
        System.out.println("method2() in ClassA");
    }
}
class ClassB extends ClassA {
    static void method1() {
         System.out.println("method1() in ClassB");
    }
    static void method3() {
         System.out.println("method3() in ClassB");
    }
}
public class ClassC {
    public static void main(String[] args) {
        ClassA a = new ClassB();
        a.method1();    // method1() in ClassA
        a.method2();    // method2() in ClassA
        a.method3();    // compile-time error
     }
}
因為這裡的 method1()、method2()、method3() 都是 static,所以和多型無關,編譯器直接使用靜態連結(static link),而不會留到執行期才動態地決定真正該呼叫的method 為何。因為編譯器在編譯期就做必須決定 method, 所以編譯器完全依賴形式型態,這麼一來「a.method1()」等於是「ClassA.method1()」, 「a.method2()」等於是「ClassA.method2()」。
多型的英文是 polymorphism,poly 是「多」的意思,morph 是「型」的意思,這個「型」可做「型態」解。 也就是說,只有當一件事物有多種型態時,才會有的一種機制。
請尊重文章版權
本文作者:蔡學鏞
張貼日期:09/25/2002

2009年6月24日

網路程式設計 - 期末考偷偷來 ( File I / O )

相關連結 http://caterpillar.onlyfun.net/Gossip/JavaGossip-V2/JavaGossip2.htm http://home.so-net.net.tw/idealist/Java/IO.html
package onlyfun.caterpillar;
 
import java.io.*;
import java.util.*;
 
public class FileDemo {
    public static void main(String[] args) {
        try { 
            String name = "FileDemo.java";//讀取的檔案或目錄
            File file = new File(name);
            if(file.isFile()) { // 是否為檔案
                System.out.println(name + " 檔案"); 
                System.out.println(
                      file.canRead() ? "可讀 " : "不可讀 "); 
                System.out.println(
                      file.canWrite() ? "可寫 " : "不可寫 "); 
                System.out.println(
                      file.length() + "位元組"); 
                /****************************************************/
                try {    
                    //讀取檔案
                    FileReader fis = new FileReader(name);
                    BufferedReader brdFile = new BufferedReader(fis);
                    //寫入檔案
                    FileWriter fOut = new FileWriter("c.txt");
                    BufferedWriter bwrFile = new BufferedWriter(fOut);
                    
                    //一行一行讀取並儲存 
                    int n = 0;
                    String strLine;
                    String str = "";
                    while ((strLine = brdFile.readLine()) != null) {
                        
                        str += (n++) + strLine + "\n";
                        
                    }
                    
                    //將字串一行一行寫入
                    String s = "";
                    for(int x = 0 ; x < str.length(); x++){
                        
                        if(str.charAt(x) != '\n'){
                            s += str.charAt(x);
                        }else{
                            bwrFile.write(s);//寫入一行
                            bwrFile.newLine();//換行
                            s = "";//字串重新儲存
                        }
                    }
                    
                    
                    System.out.println(str);
                    
                    //關閉檔案
                    brdFile.close();
                    bwrFile.close();
                    fOut.close();
                    fis.close();
                }catch (IOException e) {}
                /****************************************************/
            } 
            else { 
                // 列出所有的檔案及目錄
                File[] files = file.listFiles(); 
                ArrayList fileList = 
                                    new ArrayList(); 
                for(int i = 0; i < files.length; i++) { 
                    // 先列出目錄 
                    if(files[i].isDirectory()) { //是否為目錄
                        // 取得路徑名
                        System.out.println("[" + 
                                files[i].getPath() + "]"); 
                    }
                    else {
                        // 檔案先存入fileList,待會再列出
                        fileList.add(files[i]); 
                    }
                } 
 
                // 列出檔案 
                for(File f: fileList) {
                    System.out.println(f.toString());
                }
                System.out.println(); 
            } 
        } 
        catch(ArrayIndexOutOfBoundsException e) { 
            System.out.println(
                        "using: java FileDemo pathname"); 
        } 
    }
}

2009年6月23日

網路程式設計 - 期末考偷偷來 ( Network I / O )

相關連結 http://caterpillar.onlyfun.net/Gossip/JavaGossip-V2/JavaGossip2.htm http://home.so-net.net.tw/idealist/Java/IO.html
//Server.java

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Server extends JFrame {
    private JTextField enterField;
    private JTextArea displayArea;
    private ObjectOutputStream output;
    private ObjectInputStream input;
    private ServerSocket server;
    private Socket connection;
    private int counter = 1;

    // set up GUI
    // 設定 GUI
    public Server() {
        super( "Server" );

        Container container = getContentPane();

        // create enterField and register listener
        // 建立 enterField 設定 傾聽
        enterField = new JTextField();
        enterField.setEditable( false );
        enterField.addActionListener(
            new ActionListener() {
                // send message to client
                // 傳送 msg 到 client
                public void actionPerformed( ActionEvent event ) {
                    sendData( event.getActionCommand() );//傳送msg
                    enterField.setText( "" );
                }
            }    
        ); 

        container.add( enterField, BorderLayout.NORTH );

        // create displayArea
        // 建立 displayArea(顯示介面)
        displayArea = new JTextArea();
        container.add(new JScrollPane( displayArea ), 
                                    BorderLayout.CENTER );

        setSize( 300, 150 );
        setVisible( true );

    } // end Server constructor

    // set up and run server 
    // 設定 和 執行 server 
    public void runServer() {
        // set up server to receive connections; process connections
        // 接收連線 ; 處理連線
        try {
            // Step 1: Create a ServerSocket.
            // Step 1: 建立 ServerSocket.
            server = new ServerSocket(12345);

            while ( true ) {
                try {
                    // Step 2: Wait for a connection.
                    // Step 2: 等待連線
                    waitForConnection();
                    // Step 3: Get input & output streams.
                    // Step 3: 得到 I/O串流
                    getStreams();
                    // Step 4: Process connection.
                    // Step 4: 處理連線
                    processConnection();
                }
                // process EOFException when client closes connection
                // 當 closes 關閉連線 處理例外 
                catch ( EOFException eofException ) {
                    System.err.println( "Server 終止連線" );
                }
                finally {
                    // Step 5: Close connection.
                    // Step 5: 關閉連線
                    closeConnection();
                    ++counter;
                }
            } // end while
        } // end try

        // process problems with I/O
        // 處理 I/O 問題
        catch ( IOException ioException ) {
            ioException.printStackTrace();
        }

    } // end method runServer

    // Step 2: wait for connection to arrive, then display connection info
    // Step 2: 等待連線到達 並且 顯示連線訊息
    private void waitForConnection() throws IOException {
        displayMessage( "等待連線...\n" );
        // allow server to accept connection
        // 允許 server 接收連線                        
        connection = server.accept(); 
        displayMessage( "連線 " + counter + " 從 : " +
                 connection.getInetAddress().getHostName() );
    }

    // Step 3: get streams to send and receive data
    // Step 3: 接收 串流 和 接收 數據
    private void getStreams() throws IOException {
        // set up output stream for objects
        // 設定 objects 的 output(輸出) stream
        output = new ObjectOutputStream( connection.getOutputStream() );
        // flush output buffer to send header information
        // 輸出訊息
        output.flush(); 

        // set up input stream for objects
        // 設定 objects 的 input(輸入) stream
        input = new ObjectInputStream( connection.getInputStream() );

        displayMessage( "\n得到 I/O stream\n" );
    }

    // Step 4: process connection with client
    // Step 4: 處理連線
    private void processConnection() throws IOException {
        // send connection successful message to client
        // 傳送 連線成功訊息 給 client
        String message = "連線成功 !";
        sendData( message );

        // enable enterField so server user can send messages
        // 設定 enterField,讓 server 可以送 msg
        enterField.setEditable( true );

        // process messages sent from client
        // 處理從 client 傳送的訊息
        do { 
            // read message and display it
            // 讀取 msg 並且顯示
            try {
                message = ( String ) input.readObject();
                displayMessage( "\n" + message );
                
                sendData("訊息送達處理中...");//收到之後輸出..
                /*
                 
                 code...答案放置位址
                 
                 */
            }
            // catch problems reading from client
            catch ( ClassNotFoundException classNotFoundException ) {
                displayMessage( "\n未知 的類型" );
            }
        } while ( !message.equals( "CLIENT>>> TERMINATE" ) );
    } // end method processConnection

    // Step 5: close streams and socket
    // Step 5: 關閉連線
    private void closeConnection() {
        displayMessage( "\n終止連線\n" );
        // disable enterField
        // enterField 功能失效
        enterField.setEditable( false ); 

        try {
            output.close();
            input.close();
            connection.close();
        } catch( IOException ioException ) {
            ioException.printStackTrace();
        }
    }

    // send message to client
    // 傳送 msg 到 client
    private void sendData( String message ) {
        // send object to client
        // 傳送 物件 到 client
        try {
            output.writeObject( "SERVER>>> " + message );
            output.flush();
            displayMessage( "\nSERVER>>> " + message );
        }
        // process problems sending object
        // 處理錯誤
        catch ( IOException ioException ) {
            displayArea.append( "\n錯誤文字物件" );
        }
    }
    
    //印出 msg
    private void displayMessage( final String messageToDisplay ) {
        displayArea.append( messageToDisplay );
        displayArea.setCaretPosition(displayArea.getText().length() );
    }

    public static void main( String args[] ) {
        Server application = new Server();
        application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        application.runServer();
    }
}

2009年6月11日

網路程式設計 2009/06/12 作業(期末考題)

2009年5月25日

網路程式設計 2009/05/26 作業

2009年5月19日

網路程式設計 2009/05/20 作業

2009年5月15日

網路程式設計 2009/05/16 作業

2009年5月12日

網路程式設計 2009/05/14 作業

2009年5月11日

網路程式設計 2009/05/12 作業

偷懶偷很大= =

2009年5月8日

網路程式設計 2009/05/10 作業

2009年5月4日

網路程式設計 2009/05/06 作業

2009年4月22日

網路程式設計 2009/04/23 作業

2009年4月21日

取亂數 - 畫蛇添足版

不要吃飽撐著沒事幹= =....