6-5 套件引用與方法產生
內容:
6-5-1 Java 套件架構與導入
VIDEO
利用傳統語言編寫程式,一套完整的應用程大多是由多個函數所構成。因此,我們可將某些特殊功能編寫成函數程式( 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 範例研討:製作工程計算器
VIDEO
( 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 範例研討:密碼設定程式
VIDEO
( 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);
}
}