Java 程式設計(一)  第 六章 方法與套件引用  上一頁    下一頁

 

6-5 套件引用與方法產生

內容:

  • 6-5-1 Java 套件架構

  • 6-5-2 套件導入 - import

  • 6-5-3 範例研討:製作工程計算器

  • 6-5-4 範例研討:密碼設定程式

6-5-1 Java 套件架構與導入

利用傳統語言編寫程式,一套完整的應用程大多是由多個函數所構成。因此,我們可將某些特殊功能編寫成函數程式(Function),再編譯成『目的檔』(Object file),讓其他程式引用,如此可減少許多應用系統開發的時程,也可達到函數重複使用的目的。一般會將所開發的函數集,以其功能歸類某些特定功能的群組,並可依照特定群組來引用,因此稱之為『庫存函數』(Library)。一套系統開發工具(如 C 語言)的強弱,其關鍵在於所提供庫存函數的多寡。某些開發工具除了提供標準庫存函數之外,也會提供某些特殊功能的函數庫,譬如,多媒體處理、繪圖功能、動畫功能等等。

既然 Java 應用系統是由多個類別所構成,我們也可以將某些常用的功能,編寫成類別,並且可重複被引用。但我們回顧一下 Java 的特性,如下:

(1) 類別內有兩個主要成員:變數與方法,如果物件(類別產生)著重於變數,則類似於『結構變數』,主要用描述真實實體的特性。如果著重於方法,則類似於『函數』功能,主要實現某一特定功能的程式設計。因此,Java 的函數庫,表示類別中較著重於方法的開發。

(2) 每一方法實現某一特定功能,一般會將功能相似的方法集中歸納於同一類別裡;即是某一類別裡可以取得相對應功能的方法。

(3) 反過來講,某一特殊功能並無法由一個類別承擔,必須由許多類別儲存較細部的分類。譬如,Windows 上的繪圖套件(awt),便需要多個類別來實現。因此,Java 將某一特定功能的類別,再組合成某一功能套件(Package

(4) Java 將所提供套件、類別、方法以目錄方式儲存,而目錄的根目錄以 java 表示,如,java.lang.String.substring()。其中 java.lang 為套件名稱(language 套件)、String 為類別名稱、另 substring() 為方法名稱。

6-6 Java 套件的結構圖,表 6-2 Java 內定的子套件(節錄部分),當然還有許多子套件陸續會被發表出來。每一子套件都針對某一特殊領域,提出許多類別。

6-12 Java 套件結構圖

6-2 Java 子套件(節錄)

  

            

java.applet

Java Apllet 套件含有 Applet 類別及其介面,可以建立 Applet/瀏覽器,以及多媒體表現平台。

java.awt

Java Abstract Windows Toolkit 套件包含所有相關視窗 GUI 的類別及介面。

java.awt.event

Java AWT 可能產生事件的類別與介面。

java.io

Java Input/Output套件包含資料輸入/輸出的類別與介面。

java.lang

Java Language 套件包含許多 Java 程式可能使用到的類別及介面;編譯時會自動導入。

java.net

Java Networking 套件幫函網路功能的類別。

java.text

包含國際各種語言顯示的類別。

java.util

Java Utilities 套件包含共用程式的類別及介面。

javax.swing

Java Swing GUI Components 套件提供支援可攜式 GUI 類別;自 Java 2 之後,大多取代 java.awt 套件。

javax.swing. event

包含 Swing 可能產生事件的類別;自 Java 2 之後,大多取代 java.awt.event 套件。

……

….

6-5-2 套件導入 - import

套件是『類別』『介面』的整合,Java 利用目錄方式來儲存不同的套件;也就是說,一個套件由一個目錄樹來整合該套件之下的類別,又利用目錄整合同一類別底下的方法。引用套件時,必須在程式的第一行開始利用 import 導入套件,語法如下:

導入套件語法:

範例:

imort packetName.subPacket.className;

import packetName.*;

import java.util.Scanner;

import java.util.*;

第一行表示導入 packageName 套件中的子套件(subPacket)內的 className 類別,這種表示法最完整。但如果同一子套件內多個類別時,也可簡化 packetName.*,其中『*』表示在此目錄之下所有的意思。

Java 語言中,除了 java.lang 套件會自動導入,而不用 import 標明外,其他套件都必須利用 import 命令導入。當套件內類別被導入後,有兩種呼叫方法:

(1) 物件方法:利用 new 命令,將類別衍生出物件,原類別上所描述的方法,便隨之轉換成物件方法。使用者可以利用物件方法引用所需的方法。

(2) 類別方法:不經由 new 產生物件,而使用者直接呼叫類別內的方法。許多較常用功能的套件都採用此方法,譬如 java.lang 套件內的方法。

6-5-3 範例研討:製作工程計算器

A)程式功能:Ex6_5.java

請製作一套工程計算器,使用者輸入數值後,可選擇 log()log10()sqrt()sin()cos() tan() 等函數計算,並輸出顯示其結果,期望操作介面如下:

B)製作技巧研討:

本系統需引用包含有三角函數的數學套件(java.lang.Math),與允許鍵盤輸入套件,吾人選用 java.util.Scanner;當然採用 java.io 套件亦可。另外,系統希望能重複選擇輸入使用,需利用 while 迴圈判斷是否結束,與 switch/case 判斷選擇項目,並處理相關事項。選單視窗會重複出現,吾人可將其編寫成函數呼叫(disp_men());但它僅輸出顯示,則沒有引數與傳回值。

C)程式範例:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

//Ex6_5.java

 

import java.lang.*;            // 導入子套件 (包含 Math 類別)

import java.util.Scanner;       // 導入套件內的類別

public class Ex6_5 {

    public static void main(String args[]) {

 

        /* 利用套件內類別 java.util.Sacnner 產生物件 keyin */

        Scanner keyin = new Scanner(System.in);

        double value, ans=0;

        int select;

        disp_men();

      

        /* 呼叫引用 keyin 的物件方法 nextInt() */

        select = keyin.nextInt();

        while( select != 7) {

             System.out.printf("輸入一個數值 (注意三角函數範圍) =>");

 

             /* 呼叫 keyin nextDouble 物件方法 */

             value = keyin.nextDouble();

             switch(select) {

                 case 1:

                     /* 直接引用類別 Math 的類別方法 */

                     ans = Math.log(value);

                     System.out.printf("log(%.2f) = %.2f\n", value, ans);

                     break;

                 case 2:

                     /* 直接引用類別 Math 的類別方法 */

                     ans = Math.log10(value);

                     System.out.printf("log10(%.2f) = %.2f\n", value, ans);

                     break;

                 case 3:

                      /* 直接引用類別 Math 的類別方法 */

                     ans = Math.sqrt(value);

                     System.out.printf("sqrt(%.2f) = %.2f\n", value, ans);

                     break;

                 case 4:

                     ans = Math.sin(value);

                     System.out.printf("sin(%.2f) = %.2f\n", value, ans);

                     break;

                 case 5:

                     ans = Math.cos(value);

                     System.out.printf("cos(%.2f) = %.2f\n", value, ans);

                     break;

                 case 6:

                     ans = Math.tan(value);

                     System.out.printf("tan(%.2f) = %.2f\n", value, ans);

                     break;

                 default:

                     System.out.printf("錯誤輸入 \n”);

              }

              disp_men();

              select = keyin.nextInt();

         }

         System.out.print("== 謝謝使用 歡迎再度光臨 ==\n");

     }

      static void disp_men() {

           System.out.printf("\n*** 工程計算器提供有下列功能 ***\n");

           System.out.printf("(1) log  函數\t (2) log10() 函數\n");

           System.out.printf("(3) sqrt 函數\t (4) sin()   函數\n");

           System.out.printf("(5) cos  函數\t (6) tan()   函數\n");

           System.out.printf("(7) 離開系統\n");

           System.out.printf("請選擇輸入 =>");

      }

}

(D) 程式重點說明:

(1) 3 import java.lang.*;。導入 java.lang 下的所有類別;該套件系統會自動導入可不用再 import

(2) 4 import java.util.Scanner;。僅導入 java.util 套件下 Scanner 類別,其他未被導入,可減少佔用記憶體空間。

(3) 9 Scanner keyin = new Scanner(System.in);。利用 Scanner 類別宣告產生 keyin 物件,keyin 物件繼承了 Scanner 類別的所有方法成員(Method member)。

(4) 12 disp_men();。呼叫 disp_mem() 函數,該函數無傳回值(void),也不需要傳任何引數。

(5) 15 select = keyin.nextInt();。呼叫 keyin 物件內的 nextInt() 物件方法。

(6) 24 ans = Math.log(value);。直接呼叫 Math 類別內的 log() 類別方法。

6-5-4 範例研討:密碼設定程式

A)程式功能:Ex6_6.java

一般資訊系統大多利用『帳號/密碼』過濾用戶的身份。用戶輸入帳號與密碼,系統檢視密碼是否正確,正確的話,同意用戶登入系統;否則會拒絕登入。如此一來,系統需要紀錄用戶密碼,作為判斷用戶身份之依據。但系統如果以明文儲存用戶密碼,他人只要入侵系統就可以觀察到所有用戶的密碼,因此密碼是不可以『明文儲存』的。也就是說,密碼必須經過加密或雜湊計算後,成為一串亂文格式再儲存。但密碼如設定太短的話,所產生的亂文變化就不大,有心人還是可以猜測出密碼。但一般人為了方便記憶,又不喜歡設定太長的密碼。

『醃製法』密碼計算就是為了解決這個問題。醃製法是系統產生一個亂數稱之為『鹽』,『鹽』與密碼明文串接成一個較長的字串,此新字串經過加密或雜湊演算後,再儲存於系統。請製作一套『醃製法』密碼儲存系統,利用使用者輸入密碼明文後,與系統產生一個『鹽』,再將密碼與鹽組合為另一字串,利用此字串產生一個雜湊值,並印出結果;接著,假設使用者欲進入系統,如密碼輸入正確,則允許進入系統;否則拒絕進入。期望操作介面如下:

D:\Java1_book\chap6>javac  -encoding  utf8  Ex6_6.java

 

D:\Java1_book\chap6>java Ex6_6

請輸入使用者名稱 =>user01

請輸入密碼明文 =>123456

產生鹽亂數 = 942 儲存於電腦系統內

密碼明文與鹽組合 = 123456942

user01 密碼雜湊 = -1867376844

 

請輸入密碼 (驗證密碼是否正確) =>123456

由系統中取出鹽 = 942

輸入密碼與鹽結合後 = 123456942

輸入密碼雜湊值 = -1867376844

user01 密碼設定正確,該帳戶可使用

B)製作技巧提示:

6-7 為密碼雜湊值產生方法,電腦的密碼系統紀錄著每位使用者的『帳戶名稱』、『密碼雜湊值』與『鹽』。設定密碼的程序是,使用者輸入密碼明文,與系統所產生的『鹽』串接後,再經過『雜湊演算法』計算得到一串固定長度的雜湊值,也將產生的雜湊值與鹽儲存於密碼檔案內。

6-15 密碼雜湊值的產生方法。

當使用者欲進入系統,則輸入帳戶名稱(如 tsnien)與密碼;系統則由密碼檔案搜尋出該帳戶的『鹽』,再與使用者所輸入的『密碼』相連結之後,再經過相同的雜湊演算法計算,得到雜湊值,此值與密碼檔案內的『密碼雜湊值』相同的話,則判斷輸入密碼正確;否則拒絕該使用者登入。吾人將以上所敘述的運作程序,編寫虛擬碼如下:

導入相關套件(java.util.*;);

宣告紀錄檔:帳號(String name)、鹽(String salt)、密碼雜湊值(int hash_pas);

宣告相關變數與物件;

/* 帳號/密碼設定程式 */

讀取使用帳號(name);

讀取使用者設定密碼(passwd1);

產生鹽亂數(int value1 = 1 + (int)(Math.random()* 999));

轉換鹽亂數成字串(salt  = String.valueOf(value1));

鹽與密碼明文連結(passwd2 = passwd1.concat(salt));

產生密碼雜湊值(hash_pas = passwd2.hashCode());

輸出顯示該帳號(name)、密碼雜湊值(hash_pas)與鹽(salt);

/* 密碼驗證程式 */

讀取使用者輸入密碼(passwd1);

鹽與密碼明文連結(passwd2 = passwd1.concat(salt));

產生密碼雜湊值(test_pas = passwd2.hashCode());

if (test_pas == hash_pas)

顯示 "== 歡迎光臨 藝術化資訊系統 =="

else

顯示 "密碼不正確, 拒絕進入系統"

(C) 程式範例:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

//Ex6_6.java

/* 請製作一套密碼產生系統,當使用者輸入明文密碼,系統則會產生結果並印出 */

 

import java.util.Scanner;

public class Ex6_6 {

    public static void main(String args[]) {

 

        Scanner keyin = new Scanner(System.in);

        String name, key;               //登錄使用者名稱,

        int hash_pas;                   // 登錄密碼雜湊值

        String passwd1, passwd2;

        int value1, value2;

        System.out.printf("請輸入使用者名稱 =>");

        name = keyin.nextLine();

 

        System.out.printf("請輸入密碼明文 =>");

        passwd1 = keyin.nextLine();

        value1 = 1 + (int)(Math.random()* 999);

        key = String.valueOf(value1);

              System.out.printf("產生鹽亂數 = %s 儲存於電腦系統內\n", key);

        passwd2 = passwd1.concat(key);

        System.out.printf("密碼明文與鹽組合 = %s\n", passwd2);

        hash_pas = passwd2.hashCode();

        System.out.printf("%s 密碼雜湊 = %d\n", name, hash_pas);

 

        System.out.printf("\n請輸入密碼 (驗證密碼是否正確) =>");

        passwd1 = keyin.nextLine();

              System.out.printf("由系統中取出鹽 = %s \n", key);

        passwd2 = passwd1.concat(key);

              System.out.printf("輸入密碼與鹽結合後 = %s\n", passwd2);

        value2 = passwd2.hashCode();

              System.out.printf("輸入密碼雜湊值 = %d\n", value2);

        if (value2 == hash_pas)

            System.out.printf("%s 密碼設定正確,該帳戶可使用 \n", name);

        else

            System.out.printf("%s 密碼設定不正確, 請重新設定\n", name);

    }

}

翻轉工作室:粘添壽

 

Java 程式設計(一) 含程式邏輯

 

 

翻轉電子書系列: