當前位置:首頁 » 編程軟體 » 編譯成功的例子

編譯成功的例子

發布時間: 2024-07-18 11:49:49

❶ 如何用maven將java8寫的代碼編譯為java6平台的

在一般的Java應用開發過程中,開發人員使用Java的方式比較簡單。打開慣用的IDE,編寫Java源代碼,再利用IDE提供的功能直接運行Java 程序就可以了。這種開發模式背後的過程是:開發人員編寫的是Java源代碼文件(.java),IDE會負責調用Java的編譯器把Java源代碼編譯成平台無關的位元組代碼(byte code),以類文件的形式保存在磁碟上(.class)。Java虛擬機(JVM)會負責把Java位元組代碼載入並執行。Java通過這種方式來實現其「編寫一次,到處運行(Write once, run anywhere)」 的目標。Java類文件中包含的位元組代碼可以被不同平台上的JVM所使用。Java位元組代碼不僅可以以文件形式存在於磁碟上,也可以通過網路方式來下載,還可以只存在於內存中。JVM中的類載入器會負責從包含位元組代碼的位元組數組(byte[])中定義出Java類。在某些情況下,可能會需要動態的生成 Java位元組代碼,或是對已有的Java位元組代碼進行修改。這個時候就需要用到本文中將要介紹的相關技術。首先介紹一下如何動態編譯Java源文件。
動態編譯Java源文件
在一般情況下,開發人員都是在程序運行之前就編寫完成了全部的Java源代碼並且成功編譯。對有些應用來說,Java源代碼的內容在運行時刻才能確定。這個時候就需要動態編譯源代碼來生成Java位元組代碼,再由JVM來載入執行。典型的場景是很多演算法競賽的在線評測系統(如PKU JudgeOnline),允許用戶上傳Java代碼,由系統在後台編譯、運行並進行判定。在動態編譯Java源文件時,使用的做法是直接在程序中調用Java編譯器。
JSR 199引入了Java編譯器API。如果使用JDK 6的話,可以通過此API來動態編譯Java代碼。比如下面的代碼用來動態編譯最簡單的Hello World類。該Java類的代碼是保存在一個字元串中的。
01 public class CompilerTest {
02 public static void main(String[] args) throws Exception {
03 String source = "public class Main { public static void main(String[] args) {System.out.println(\"Hello World!\");} }";
04 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
05 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
06 StringSourceJavaObject sourceObject = newCompilerTest.StringSourceJavaObject("Main", source);
07 Iterable< extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
08 CompilationTask task = compiler.getTask(null, fileManager, null,null, null, fileObjects);
09 boolean result = task.call();
10 if (result) {
11 System.out.println("編譯成功。");
12 }
13 }
14
15 static class StringSourceJavaObject extends SimpleJavaFileObject {
16
17 private String content = null;
18 public StringSourceJavaObject(String name, String content) ??throwsURISyntaxException {
19 super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
20 this.content = content;
21 }
22
23 public CharSequence getCharContent(boolean ignoreEncodingErrors) ??throws IOException {
24 return content;
25 }
26 }
27 }
如果不能使用JDK 6提供的Java編譯器API的話,可以使用JDK中的工具類com.sun.tools.javac.Main,不過該工具類只能編譯存放在磁碟上的文件,類似於直接使用javac命令。
另外一個可用的工具是Eclipse JDT Core提供的編譯器。這是Eclipse Java開發環境使用的增量式Java編譯器,支持運行和調試有錯誤的代碼。該編譯器也可以單獨使用。Play框架在內部使用了JDT的編譯器來動態編譯Java源代碼。在開發模式下,Play框架會定期掃描項目中的Java源代碼文件,一旦發現有修改,會自動編譯 Java源代碼。因此在修改代碼之後,刷新頁面就可以看到變化。使用這些動態編譯的方式的時候,需要確保JDK中的tools.jar在應用的 CLASSPATH中。
下面介紹一個例子,是關於如何在Java裡面做四則運算,比如求出來(3+4)*7-10的值。一般的做法是分析輸入的運算表達式,自己來模擬計算過程。考慮到括弧的存在和運算符的優先順序等問題,這樣的計算過程會比較復雜,而且容易出錯。另外一種做法是可以用JSR 223引入的腳本語言支持,直接把輸入的表達式當做JavaScript或是JavaFX腳本來執行,得到結果。下面的代碼使用的做法是動態生成Java源代碼並編譯,接著載入Java類來執行並獲取結果。這種做法完全使用Java來實現。
01 private static double calculate(String expr) throws CalculationException {
02 String className = "CalculatorMain";
03 String methodName = "calculate";
04 String source = "public class " + className
05 + " { public static double " + methodName + "() { return " + expr +"; } }";
06 //省略動態編譯Java源代碼的相關代碼,參見上一節
07 boolean result = task.call();
08 if (result) {
09 ClassLoader loader = Calculator.class.getClassLoader();
10 try {
11 Class<?> clazz = loader.loadClass(className);
12 Method method = clazz.getMethod(methodName, new Class<?>[] {});
13 Object value = method.invoke(null, new Object[] {});
14 return (Double) value;
15 } catch (Exception e) {
16 throw new CalculationException("內部錯誤。");
17 }
18 } else {
19 throw new CalculationException("錯誤的表達式。");
20 }
21 }
上面的代碼給出了使用動態生成的Java位元組代碼的基本模式,即通過類載入器來載入位元組代碼,創建Java類的對象的實例,再通過Java反射API來調用對象中的方法。
Java位元組代碼增強
Java 位元組代碼增強指的是在Java位元組代碼生成之後,對其進行修改,增強其功能。這種做法相當於對應用程序的二進制文件進行修改。在很多Java框架中都可以見到這種實現方式。Java位元組代碼增強通常與Java源文件中的註解(annotation)一塊使用。註解在Java源代碼中聲明了需要增強的行為及相關的元數據,由框架在運行時刻完成對位元組代碼的增強。Java位元組代碼增強應用的場景比較多,一般都集中在減少冗餘代碼和對開發人員屏蔽底層的實現細節上。用過JavaBeans的人可能對其中那些必須添加的getter/setter方法感到很繁瑣,並且難以維護。而通過位元組代碼增強,開發人員只需要聲明Bean中的屬性即可,getter/setter方法可以通過修改位元組代碼來自動添加。用過JPA的人,在調試程序的時候,會發現實體類中被添加了一些額外的 域和方法。這些域和方法是在運行時刻由JPA的實現動態添加的。位元組代碼增強在面向方面編程(AOP)的一些實現中也有使用。

❷ 關於如何判斷gcc之類的編譯器的編譯結果

我們再使用gcc編譯的時候可以讓他的輸出信息保存到文件當中

gccmain.c-omain&>status.txt

上面的命令就是將gcc編譯的信息保存到status.txt文件中,然後我們再程序中讀取文件,看文件是否有內容,沒有內容就說明沒有報錯和警告,編譯成功。有內容就對每一行內容進行判斷,看是warring還是error,只有warring也代表編譯成功,有error代表編譯失敗,然後把這些報錯信息都列印出來就好了。

下面看一下例子:

❸ Java榪涢樁錛歋E6璋冪敤緙栬瘧鍣ㄧ殑涓ょ嶆柟娉昜1]

銆銆鍦ㄥ緢澶欽ava搴旂敤涓闇瑕佸湪紼嬪簭涓璋冪敤Java緙栬瘧鍣ㄦ潵緙栬瘧鍜岃繍琛 浣嗗湪鏃╂湡鐨勭増鏈涓錛圝ava SE 鍙婁互鍓嶇増鏈錛変腑鍙鑳介氳繃tools jar涓鐨 sun tools javac鍖呮潵璋冪敤Java緙栬瘧鍣 浣嗙敱浜巘ools jar涓嶆槸鏍囧噯鐨凧ava搴 鍦ㄤ嬌鐢ㄦ椂蹇呴』瑕佽劇疆榪欎釜jar鐨勮礬寰 鑰屽湪Java SE 涓涓烘垜浠鎻愪緵浜嗘爣鍑嗙殑鍖呮潵鎿嶄綔Java緙栬瘧鍣 榪欏氨鏄痡avax tools鍖 浣跨敤榪欎釜鍖 鎴戜滑鍙浠ヤ笉鐢ㄥ皢jar鏂囦歡璺寰勬坊鍔犲埌classpath涓浜

銆銆涓 浣跨敤JavaCompiler鎺ュ彛鏉ョ紪璇慗ava婧愮▼搴

銆銆浣跨敤Java API鏉ョ紪璇慗ava婧愮▼搴忔湁寰堝氭柟娉 鐜板湪璁╂垜浠鏉ョ湅涓縐嶆渶綆鍗曠殑鏂規硶 閫氳繃JavaCompiler榪涜岀紪璇

銆銆鎴戜滑鍙浠ラ氳繃ToolProvider綾葷殑闈欐佹柟娉昰etSystemJavaCompiler鏉ュ緱鍒頒竴涓狫avaCompiler鎺ュ彛鐨勫疄渚

銆銆JavaCompiler piler = ToolProvider getSystemJavaCompiler();

銆銆JavaCompiler涓鏈鏍稿績鐨勬柟娉曟槸run 閫氳繃榪欎釜鏂規硶鍙浠ョ紪璇慾ava婧愮▼搴 榪欎釜鏂規硶鏈 涓鍥哄畾鍙傛暟鍜 涓鍙鍙樺弬鏁幫紙鍙鍙樺弬鏁版槸浠嶫ave SE 寮濮嬫彁渚涚殑涓涓鏂扮殑鍙傛暟綾誨瀷 鐢╰ype鈥 argu琛ㄧず錛 鍓 涓鍙傛暟鍒嗗埆鐢ㄦ潵涓簀ava緙栬瘧鍣ㄦ彁渚涘弬鏁 寰楀埌Java緙栬瘧鍣ㄧ殑杈撳嚭淇℃伅浠ュ強鎺ユ敹緙栬瘧鍣ㄧ殑閿欒淇℃伅 鍚庨潰鐨勫彲鍙樺弬鏁板彲浠ヤ紶鍏ヤ竴涓鎴栧氫釜Java婧愮▼搴忔枃浠 濡傛灉run緙栬瘧鎴愬姛 榪斿洖

銆銆int run(InputStream in OutputStream out OutputStream err String arguments)

銆銆濡傛灉鍓 涓鍙傛暟浼犲叆鐨勬槸null 閭d箞run鏂規硶灝嗕互鏍囧噯鐨勮緭鍏 杈撳嚭浠f浛 鍗砈ystem in System out鍜孲ystem err 濡傛灉鎴戜滑瑕佺紪璇戜竴涓猼est java鏂囦歡 騫跺皢浣跨敤鏍囧噯杈撳叆杈撳嚭 run鐨勪嬌鐢ㄦ柟娉曞備笅

銆銆int results = tool run(null null null test java );

銆銆涓嬮潰鏄浣跨敤JavaCompiler鐨勫畬鏁翠唬鐮

銆銆import java io *;銆銆import javax tools *;銆銆public class test_pilerapi銆銆{銆 銆public static void main(String args[]) throws IOException銆 銆{銆 銆JavaCompiler piler = ToolProvider getSystemJavaCompiler();銆 銆int results = piler run(null null null test java );銆 銆System out println((results == )? 緙栬瘧鎴愬姛 : 緙栬瘧澶辮觸 );銆 銆// 鍦ㄧ▼搴忎腑榪愯宼est銆 銆Runtime run = Runtime getRuntime();銆 銆Process p = run exec( java test );銆 銆BufferedInputStream in = new BufferedInputStream(p getInputStream());銆 銆BufferedReader br = new BufferedReader(new InputStreamReader(in));銆 銆String s;銆 銆while ((s = br readLine()) != null)銆 銆System out println(s);銆 銆}銆銆}銆銆public class test銆銆{銆 銆public static void main(String[] args) throws Exception銆 銆{銆 銆System out println( JavaCompiler嫻嬭瘯鎴愬姛錛 );銆 銆}銆銆}

銆銆緙栬瘧鎴愬姛鐨勮緭鍑虹粨鏋

銆銆緙栬瘧鎴愬姛

銆銆JavaCompiler嫻嬭瘯鎴愬姛

銆銆緙栬瘧澶辮觸鐨勮緭鍑虹粨鏋

銆銆test java: : 鎵句笉鍒扮﹀彿

銆銆絎﹀彿 鏂規硶 printlnln(java lang String)

銆銆浣嶇疆 綾 java io PrintStream

銆銆System out printlnln( JavaCompiler嫻嬭瘯鎴愬姛錛 );

銆銆^

銆銆 閿欒

銆銆緙栬瘧澶辮觸

銆銆浜 浣跨敤StandardJavaFileManager緙栬瘧Java婧愮▼搴

銆銆鍦ㄧ涓閮ㄥ垎鎴戜滑璁ㄨ鴻皟鐢╦ava緙栬瘧鍣ㄧ殑鏈瀹規槗鐨勬柟娉 榪欑嶆柟娉曞彲浠ュ緢濂藉湴宸ヤ綔 浣嗗畠紜涓嶈兘鏇存湁鏁堝湴寰楀埌鎴戜滑鎵闇瑕佺殑淇℃伅 濡傛爣鍑嗙殑杈撳叆 杈撳嚭淇℃伅 鑰屽湪Java SE 涓鏈濂界殑鏂規硶鏄浣跨敤StandardJavaFileManager綾 榪欎釜綾誨彲浠ュ緢濂藉湴鎺у埗杈撳叆 杈撳嚭 騫朵笖鍙浠ラ氳繃DiagnosticListener寰楀埌璇婃柇淇℃伅 鑰孌iagnosticCollector綾誨氨鏄痩istener鐨勫疄鐜

銆銆浣跨敤StandardJavaFileManager闇瑕佷袱姝 棣栧厛寤虹珛涓涓狣iagnosticCollector瀹炰緥浠ュ強閫氳繃JavaCompiler鐨刧etStandardFileManager()鏂規硶寰楀埌涓涓猄tandardFileManager瀵硅薄 鏈鍚庨氳繃CompilationTask涓鐨刢all鏂規硶緙栬瘧婧愮▼搴

銆銆鍦ㄤ嬌鐢ㄨ繖縐嶆柟娉曡皟鐢↗ava緙栬瘧鏃舵渶澶嶆潅鐨勬柟娉曞氨鏄痝etTask 涓嬮潰璁╂垜浠璁ㄨ轟竴涓媑etTask鏂規硶 榪欎釜鏂規硶鏈夊備笅鎵紺虹殑 涓鍙傛暟

銆銆getTask(Writer out JavaFileManager fileManager 銆銆DiagnosticListener diagnosticListener 銆銆Iterable options 銆銆Iterable classes 銆銆Iterable pilationUnits)

銆銆榪欎簺鍙傛暟澶у氭暟閮藉彲涓簄ull 瀹冧滑鐨勫惈涔夋墍涓

銆銆路out: 鐢ㄤ簬杈撳嚭閿欒鐨勬祦 榛樿ゆ槸System err

銆銆路fileManager: 鏍囧噯鐨勬枃浠剁$悊

銆銆路diagnosticListener: 緙栬瘧鍣ㄧ殑榛樿よ屼負

銆銆路options: 緙栬瘧鍣ㄧ殑閫夐」

銆銆路classes 鍙備笌緙栬瘧鐨刢lass

銆銆鏈鍚庝竴涓鍙傛暟pilationUnits涓嶈兘涓簄ull 鍥犱負榪欎釜瀵硅薄淇濆瓨浜嗕綘鎯崇紪璇戠殑Java鏂囦歡

銆銆鍦ㄤ嬌鐢ㄥ畬getTask鍚 闇瑕侀氳繃StandardJavaFileManager鐨刧etJavaFileObjectsFromFiles鎴杇etJavaFileObjectsFromStrings鏂規硶寰楀埌pilationUnits瀵硅薄 璋冪敤榪欎袱涓鏂規硶鐨勬柟寮忓備笅

銆銆Iterable getJavaFileObjectsFromFiles(銆銆Iterable files)銆銆Iterable getJavaFileObjectsFromStrings(銆銆Iterable names)銆銆String[] filenames = 鈥;銆銆Iterable pilationUnits =銆銆fileManager getJavaFileObjectsFromFiles(Arrays asList(filenames));銆銆JavaCompiler CompilationTask task = piler getTask(null fileManager 銆銆diagnostics options null pilationUnits);銆銆鏈鍚庨渶瑕佸叧闂璮ileManager close();

銆銆涓嬮潰鏄涓涓瀹屾暣鐨勬紨紺虹▼搴

銆銆import java io *;銆銆import java util *;銆銆import javax tools *;銆銆public class test_pilerapi銆銆{銆 銆private static void pilejava() throws Exception銆 銆{銆 銆JavaCompiler piler = ToolProvider getSystemJavaCompiler();銆 銆// 寤虹珛DiagnosticCollector瀵硅薄銆 銆DiagnosticCollector diagnostics = new DiagnosticCollector();銆 銆StandardJavaFileManager fileManager = piler getStandardFileManager(diagnostics null null);銆 銆// 寤虹珛鐢ㄤ簬淇濆瓨琚緙栬瘧鏂囦歡鍚嶇殑瀵硅薄銆 銆// 姣忎釜鏂囦歡琚淇濆瓨鍦ㄤ竴涓浠嶫avaFileObject緇ф壙鐨勭被涓銆 銆Iterable pilationUnits = fileManager銆 銆 getJavaFileObjectsFromStrings(Arrays asList( test java ));銆 銆JavaCompiler CompilationTask task = piler getTask(null fileManager 銆 銆diagnostics null null pilationUnits);銆 銆// 緙栬瘧婧愮▼搴忋 銆boolean success = task call();銆 銆fileManager close();銆 銆System out println((success)? 緙栬瘧鎴愬姛 : 緙栬瘧澶辮觸 );銆 銆}銆銆 public static void main(String args[]) throws Exception銆 銆{銆 銆pilejava();銆銆 }銆銆}

銆銆濡傛灉鎯沖緱鍒板叿浣撶殑緙栬瘧閿欒 鍙浠ュ笵iagnostics榪涜屾壂鎻 浠g爜濡備笅

銆銆for (Diagnostic diagnostic : diagnostics getDiagnostics())銆銆System out printf(銆銆 Code: %s%n +銆銆 Kind: %s%n +銆銆 Position: %s%n +銆銆 Start Position: %s%n +銆銆 End Position: %s%n +銆銆 Source: %s%n +銆銆 Message: %s%n 銆銆diagnostic getCode() diagnostic getKind() 銆銆diagnostic getPosition() diagnostic getStartPosition() 銆銆diagnostic getEndPosition() diagnostic getSource() 銆銆diagnostic getMessage(null));銆銆琚緙栬瘧鐨則est java浠g爜濡備笅 銆銆public class test銆銆{銆銆 public static void main(String[] args) throws Exception銆 銆{銆 銆aa; //閿欒璇鍙ャ 銆System out println( JavaCompiler嫻嬭瘯鎴愬姛錛 );銆 銆}銆銆}

銆銆鍦ㄨ繖孌典唬鐮佷腑澶氬啓浜嗕釜aa 寰楀埌鐨勭紪璇戦敊璇涓

銆銆Code: piler err not stmt銆銆Kind: ERROR銆銆Position: 銆銆Start Position: 銆銆End Position: 銆銆Source: test java銆銆Message: test java: : 涓嶆槸璇鍙ャ銆Success: false

銆銆閫氳繃JavaCompiler榪涜岀紪璇戦兘鏄鍦ㄥ綋鍓嶇洰褰曚笅鐢熸垚 class鏂囦歡 鑰屼嬌鐢ㄧ紪璇戦夐」鍙浠ユ敼鍙樿繖涓榛樿ょ洰褰 緙栬瘧閫夐」鏄涓涓鍏冪礌涓篠tring綾誨瀷鐨処terable闆嗗悎 濡傛垜浠鍙浠ヤ嬌鐢ㄥ備笅浠g爜鍦―鐩樻牴鐩褰曚笅鐢熸垚 class鏂囦歡

銆銆Iterable options = Arrays asList( d d:\ );銆銆JavaCompiler CompilationTask task = piler getTask(null fileManager 銆銆diagnostics options null pilationUnits);

銆銆鍦ㄤ笂闈㈢殑渚嬪瓙涓璷ptions澶勭殑鍙傛暟涓簄ull 鑰岃佷紶閫掔紪璇戝櫒鐨勫弬鏁 灝遍渶瑕佸皢options浼犲叆

銆銆鏈夋椂鎴戜滑緙栬瘧涓涓狫ava婧愮▼搴忔枃浠 鑰岃繖涓婧愮▼搴忔枃浠墮渶瑕佸彟鍑犱釜Java鏂囦歡 鑰岃繖浜汮ava鏂囦歡鍙堝湪鍙﹀栦竴涓鐩褰 閭d箞榪欏氨闇瑕佷負緙栬瘧鍣ㄦ寚瀹氳繖浜涙枃浠舵墍鍦ㄧ殑鐩褰

銆銆Iterable options = Arrays asList( sourcepath d:\src );

銆銆涓婇潰鐨勪唬鐮佹寚瀹氱殑琚緙栬瘧Java鏂囦歡鎵渚濊禆鐨勬簮鏂囦歡鎵鍦ㄧ殑鐩褰

lishixin/Article/program/Java/hx/201311/27239

❹ MD5是如何編譯的

MD5簡介

MD5的全稱是Message-Digest Algorithm 5,在90年代初由MIT的計算機科學實驗室和RSA Data Security Inc發明,經MD2、MD3和MD4發展而來。

Message-Digest泛指位元組串(Message)的Hash變換,就是把一個任意長度的位元組串變換成一定長的大整數。請注意我使用了「位元組串」而不是「字元串」這個詞,是因為這種變換只與位元組的值有關,與字元集或編碼方式無關。

MD5將任意長度的「位元組串」變換成一個128bit的大整數,並且它是一個不可逆的字元串變換演算法,換句話說就是,即使你看到源程序和演算法描述,也無法將一個MD5的值變換回原始的字元串,從數學原理上說,是因為原始的字元串有無窮多個,這有點象不存在反函數的數學函數。

MD5的典型應用是對一段Message(位元組串)產生fingerprint(指紋),以防止被「篡改」。舉個例子,你將一段話寫在一個叫readme.txt文件中,並對這個readme.txt產生一個MD5的值並記錄在案,然後你可以傳播這個文件給別人,別人如果修改了文件中的任何內容,你對這個文件重新計算MD5時就會發現。如果再有一個第三方的認證機構,用MD5還可以防止文件作者的「抵賴」,這就是所謂的數字簽名應用。

MD5還廣泛用於加密和解密技術上,在很多操作系統中,用戶的密碼是以MD5值(或類似的其它演算法)的方式保存的,用戶Login的時候,系統是把用戶輸入的密碼計算成MD5值,然後再去和系統中保存的MD5值進行比較,而系統並不「知道」用戶的密碼是什麼。

一些黑客破獲這種密碼的方法是一種被稱為「跑字典」的方法。有兩種方法得到字典,一種是日常搜集的用做密碼的字元串表,另一種是用排列組合方法生成的,先用MD5程序計算出這些字典項的MD5值,然後再用目標的MD5值在這個字典中檢索。

即使假設密碼的最大長度為8,同時密碼只能是字母和數字,共26+26+10=62個字元,排列組合出的字典的項數則是P(62,1)+P(62,2)….+P(62,8),那也已經是一個很天文的數字了,存儲這個字典就需要TB級的磁碟組,而且這種方法還有一個前提,就是能獲得目標賬戶的密碼MD5值的情況下才可以。

在很多電子商務和社區應用中,管理用戶的Account是一種最常用的基本功能,盡管很多Application Server提供了這些基本組件,但很多應用開發者為了管理的更大的靈活性還是喜歡採用關系資料庫來管理用戶,懶惰的做法是用戶的密碼往往使用明文或簡單的變換後直接保存在資料庫中,因此這些用戶的密碼對軟體開發者或系統管理員來說可以說毫無保密可言,本文的目的是介紹MD5的Java Bean的實現,同時給出用MD5來處理用戶的Account密碼的例子,這種方法使得管理員和程序設計者都無法看到用戶的密碼,盡管他們可以初始化它們。但重要的一點是對於用戶密碼設置習慣的保護。

有興趣的讀者可以從這里取得MD5也就是RFC 1321的文本。 http://www.ietf.org/rfc/rfc1321.txt

實現策略

MD5的演算法在RFC1321中實際上已經提供了C的實現,我們其實馬上就能想到,至少有兩種用Java實現它的方法,第一種是,用Java語言重新寫整個演算法,或者再說簡單點就是把C程序改寫成Java程序。第二種是,用JNI(Java Native Interface)來實現,核心演算法仍然用這個C程序,用Java類給它包個殼。

但我個人認為,JNI應該是Java為了解決某類問題時的沒有辦法的辦法(比如與操作系統或I/O設備密切相關的應用),同時為了提供和其它語言的互操作性的一個手段。使用JNI帶來的最大問題是引入了平台的依賴性,打破了SUN所鼓吹的「一次編寫到處運行」的Java好處。因此,我決定採取第一種方法,一來和大家一起嘗試一下「一次編寫到處運行」的好處,二來檢驗一下Java 2現在對於比較密集的計算的效率問題。

實現過程

限於這篇文章的篇幅,同時也為了更多的讀者能夠真正專注於問題本身,我不想就某一種Java集成開發環境來介紹這個Java Bean的製作過程,介紹一個方法時我發現步驟和命令很清晰,我相信有任何一種Java集成環境三天以上經驗的讀者都會知道如何把這些代碼在集成環境中編譯和運行。用集成環境講述問題往往需要配很多屏幕截圖,這也是我一直對集成環境很頭疼的原因。我使用了一個普通的文本編輯器,同時使用了Sun公司標準的JDK 1.3.0 for Windows NT。

其實把C轉換成Java對於一個有一定C語言基礎的程序員並不困難,這兩個語言的基本語法幾乎完全一致.我大概花了一個小時的時間完成了代碼的轉換工作,我主要作了下面幾件事:

把必須使用的一些#define的宏定義變成Class中的final static,這樣保證在一個進程空間中的多個Instance共享這些數據
刪去了一些無用的#if define,因為我只關心MD5,這個推薦的C實現同時實現了MD2 MD3和 MD4,而且有些#if define還和C不同編譯器有關
將一些計算宏轉換成final static 成員函數。
所有的變數命名與原來C實現中保持一致,在大小寫上作一些符合Java習慣的變化,計算過程中的C函數變成了private方法(成員函數)。
關鍵變數的位長調整
定義了類和方法
需要注意的是,很多早期的C編譯器的int類型是16 bit的,MD5使用了unsigned long int,並認為它是32bit的無符號整數。而在Java中int是32 bit的,long是64 bit的。在MD5的C實現中,使用了大量的位操作。這里需要指出的一點是,盡管Java提供了位操作,由於Java沒有unsigned類型,對於右移位操作多提供了一個無符號右移:>>>,等價於C中的 >> 對於unsigned 數的處理。

因為Java不提供無符號數的運算,兩個大int數相加就會溢出得到一個負數或異常,因此我將一些關鍵變數在Java中改成了long類型(64bit)。我個人認為這比自己去重新定義一組無符號數的類同時重載那些運算符要方便,同時效率高很多並且代碼也易讀,OO(Object Oriented)的濫用反而會導致效率低下。

限於篇幅,這里不再給出原始的C代碼,有興趣對照的讀者朋友可以去看RFC 1321。MD5.java源代碼

測試

在RFC 1321中,給出了Test suite用來檢驗你的實現是否正確:

MD5 ("") =

MD5 ("a") =

MD5 ("abc") =

MD5 ("message digest") =

MD5 ("abcdefghijklmnopqrstuvwxyz") =

……

這些輸出結果的含義是指:空字元串」」的MD5值是,字元串」a」的MD5值是……
編譯並運行我們的程序:
javac –d . MD5.java
java beartool.MD5
為了將來不與別人的同名程序沖突,我在我的程序的第一行使用了package beartool;

因此編譯命令javac –d . MD5.java 命令在我們的工作目錄下自動建立了一個beartool目錄,目錄下放著編譯成功的 MD5.class

我們將得到和Test suite同樣的結果。當然還可以繼續測試你感興趣的其它MD5變換,例如:

java beartool.MD5 1234

將給出1234的MD5值。

可能是我的計算機知識是從Apple II和Z80單板機開始的,我對大寫十六進制代碼有偏好,如果您想使用小寫的Digest String只需要把byteHEX函數中的A、B、C、D、E、F改成a、b、 c、d、e、f就可以了。

MD5據稱是一種比較耗時的計算,我們的Java版MD5一閃就算出來了,沒遇到什麼障礙,而且用肉眼感覺不出來Java版的MD5比C版的慢。

為了測試它的兼容性,我把這個MD5.class文件拷貝到我的另一台Linux+IBM JDK 1.3的機器上,執行後得到同樣結果,確實是「一次編寫到處運行了」。

Java Bean簡述

現在,我們已經完成並簡單測試了這個Java Class,我們文章的標題是做一個Java Bean。

其實普通的Java Bean很簡單,並不是什麼全新的或偉大的概念,就是一個Java的Class,盡管 Sun規定了一些需要實現的方法,但並不是強制的。而EJB(Enterprise Java Bean)無非規定了一些必須實現(非常類似於響應事件)的方法,這些方法是供EJB Container使用(調用)的。

在一個Java Application或Applet里使用這個bean非常簡單,最簡單的方法是你要使用這個類的源碼工作目錄下建一個beartool目錄,把這個class文件拷貝進去,然後在你的程序中import beartool.MD5就可以了。最後打包成.jar或.war是保持這個相對的目錄關系就行了。

Java還有一個小小的好處是你並不需要摘除我們的MD5類中那個main方法,它已經是一個可以工作的Java Bean了。Java有一個非常大的優點是她允許很方便地讓多種運行形式在同一組代碼中共存,比如,你可以寫一個類,它即是一個控制台Application和GUI Application,同時又是一個Applet,同時還是一個Java Bean,這對於測試、維護和發布程序提供了極大的方便,這里的測試方法main還可以放到一個內部類中,有興趣的讀者可以參考: http://www.cn.ibm.com/developerWorks/java/jw-tips/tip106/index.shtml

這里講述了把測試和示例代碼放在一個內部靜態類的好處,是一種不錯的工程化技巧和途徑。

把Java Bean裝到JSP里

正如我們在本文開頭講述的那樣,我們對這個MD5 Bean的應用是基於一個用戶管理,這里我們假設了一個虛擬社區的用戶login過程,用戶的信息保存在資料庫的個名為users的表中。這個表有兩個欄位和我們的這個例子有關,userid :char(20)和pwdmd5 :char(32),userid是這個表的Primary Key,pwdmd5保存密碼的MD5串,MD5值是一個128bit的大整數,表示成16進制的ASCII需要32個字元。

這里給出兩個文件,login.html是用來接受用戶輸入的form,login.jsp用來模擬使用MD5 Bean的login過程。

為了使我們的測試環境簡單起見,我們在JSP中使用了JDK內置的JDBC-ODBC Bridge Driver,community是ODBC的DSN的名字,如果你使用其它的JDBC Driver,替換掉login.jsp中的
Connection con= DriverManager.getConnection("jdbc:odbc:community", "", "");
即可。

login.jsp的工作原理很簡單,通過post接收用戶輸入的UserID和Password,然後將Password變換成MD5串,然後在users表中尋找UserID和pwdmd5,因為UserID是users表的Primary Key,如果變換後的pwdmd5與表中的記錄不符,那麼SQL查詢會得到一個空的結果集。

這里需要簡單介紹的是,使用這個Bean只需要在你的JSP應用程序的WEB-INF/classes下建立一個beartool目錄,然後將MD5.class拷貝到那個目錄下就可以了。如果你使用一些集成開發環境,請參考它們的deploy工具的說明。在JSP使用一個java Bean關鍵的一句聲明是程序中的第2行:

<jsp:useBean id='oMD5' scope='request' class='beartool.MD5'/>
這是所有JSP規范要求JSP容器開發者必須提供的標准Tag。

id=實際上是指示JSP Container創建Bean的實例時用的實例變數名。在後面的<%和%>之間的Java程序中,你可以引用它。在程序中可以看到,通過 pwdmd5=oMD5.getMD5ofStr (password)引用了我們的MD5 Java Bean提供的唯一一個公共方法: getMD5ofStr。

Java Application Server執行.JSP的過程是先把它預編譯成.java(那些Tag在預編譯時會成為java語句),然後再編譯成.class。這些都是系統自動完成和維護的,那個.class也稱為Servlet。當然,如果你願意,你也可以幫助Java Application Server去干本該它乾的事情,自己直接去寫Servlet,但用Servlet去輸出HTML那簡直是回到了用C寫CGI程序的惡夢時代。

如果你的輸出是一個復雜的表格,比較方便的方法我想還是用一個你所熟悉的HTML編輯器編寫一個「模板」,然後在把JSP代碼「嵌入」進去。盡管這種JSP代碼被有些專家指責為「空心粉」,它的確有個缺點是代碼比較難管理和重復使用,但是程序設計永遠需要的就是這樣的權衡。我個人認為,對於中、小型項目,比較理想的結構是把數據表示(或不嚴格地稱作WEB界面相關)的部分用JSP寫,和界面不相關的放在Bean裡面,一般情況下是不需要直接寫Servlet的。

如果你覺得這種方法不是非常的OO(Object Oriented),你可以繼承(extends)它一把,再寫一個bean把用戶管理的功能包進去。

到底能不能兼容?

我測試了三種Java應用伺服器環境,Resin 1.2.3、Sun J2EE 1.2、IBM WebSphere 3.5,所幸的是這個Java Bean都沒有任何問題,原因其實是因為它僅僅是個計算程序,不涉及操作系統,I/O設備。其實用其它語言也能簡單地實現它的兼容性的,Java的唯一優點是,你只需提供一個形態的運行碼就可以了。請注意「形態」二字,現在很多計算結構和操作系統除了語言本身之外都定義了大量的代碼形態,很簡單的一段C語言核心代碼,轉換成不同形態要考慮很多問題,使用很多工具,同時受很多限制,有時候學習一種新的「形態」所花費的精力可能比解決問題本身還多。比如光Windows就有EXE、Service、的普通DLL、COM DLL以前還有OCX等等等等,在Unix上雖說要簡單一些,但要也要提供一個.h定義一大堆宏,還要考慮不同平台編譯器版本的位長度問題。我想這是Java對我來說的一個非常重要的魅力吧。

MD5演算法說明

一、補位
二、補數據長度
三、初始化MD5參數
四、處理位操作函數
五、主要變換過程
六、輸出結果

補位:
MD5演算法先對輸入的數據進行補位,使得數據位長度LEN對512求余的結果是448。即數據擴展至K*512+448位。即K*64+56個位元組,K為整數。
具體補位操作:補一個1,然後補0至滿足上述要求。
補數據長度:
用一個64位的數字表示數據的原始長度B,把B用兩個32位數表示。這時,數
據就被填補成長度為512位的倍數。
初始化MD5參數:
四個32位整數 (A,B,C,D) 用來計算信息摘要,初始化使用的是十六進製表
示的數字
A=0X01234567
B=0X89abcdef
C=0Xfedcba98
D=0X76543210

處理位操作函數:
X,Y,Z為32位整數。
F(X,Y,Z) = X&Y|NOT(X)&Z
G(X,Y,Z) = X&Z|Y?(Z)
H(X,Y,Z) = X xor Y xor Z
I(X,Y,Z) = Y xor (X|not(Z))

主要變換過程:
使用常數組T[1 ... 64], T[i]為32位整數用16進製表示,數據用16個32位
的整數數組M[]表示。
具體過程如下:

/* 處理數據原文 */
For i = 0 to N/16-1 do

/*每一次,把數據原文存放在16個元素的數組X中. */
For j = 0 to 15 do
Set X[j] to M[i*16+j].
end /結束對J的循環

/* Save A as AA, B as BB, C as CC, and D as DD.
*/
AA = A
BB = B
CC = C
DD = D

/* 第1輪*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */

/* Do the following 16 operations. */
[ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3
22 4]
[ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7
22 8]
[ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA
11 22 12]
[ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15]
[BCDA 15 22 16]

/* 第2輪* */
/* 以 [abcd k s i]表示如下操作
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA
0 20 20]
[ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23]
[BCDA 4 20 24]
[ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA
8 20 28]
[ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA
12 20 32]

/* 第3輪*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35]
[BCDA 14 23 36]
[ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA
10 23 40]
[ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43]
[BCDA 6 23 44]
[ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47]
[BCDA 2 23 48]

/* 第4輪*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51]
[BCDA 5 21 52]
[ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55]
[BCDA 1 21 56]
[ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59]
[BCDA 13 21 60]
[ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63]
[BCDA 9 21 64]

/* 然後進行如下操作 */
A = A + AA
B = B + BB
C = C + CC
D = D + DD

end /* 結束對I的循環*/

輸出結果。

❺ 如何編譯運行一個簡單的java程序

通常開發一個java應用程序可分為三個步驟:

1.創建一個帶有文件擴展名 *.java 的源文件

1).使用編輯器(如記事本,小編使用的是notepad++),輸入以下6行文本:

1 //一個簡單的application例子:列印一行文本

2 class Hello {

3 public static void main (String args[]){

4 System.out.println("Hello Java,This is my first Java Application!");

5 }

6 }

輸入完成,如下圖所示

爪哇之路開啟成功。

熱點內容
忘記的志願者賬號和密碼如何找回來 發布:2024-11-26 01:57:46 瀏覽:205
交換機怎麼復制配置文件 發布:2024-11-26 01:51:47 瀏覽:489
輸編程 發布:2024-11-26 01:51:05 瀏覽:724
推薦類的演算法 發布:2024-11-26 01:50:22 瀏覽:917
怎麼製作ftp軟體 發布:2024-11-26 01:45:41 瀏覽:567
演算法m是誰 發布:2024-11-26 01:40:35 瀏覽:44
h1z1文件夾安裝 發布:2024-11-26 01:40:28 瀏覽:23
電話加密 發布:2024-11-26 01:39:09 瀏覽:28
hotspot源碼 發布:2024-11-26 01:33:05 瀏覽:282
日本電報密碼是多少 發布:2024-11-26 01:33:00 瀏覽:441