|
摘要: Servlet 3.0 引入了 javax.servlet.http.Part 接口,從而提供了對 multipart/form-data 類型的 HTTP 請求的直接支持,我們從此就可以擺脫諸如 Apache Commons FileUpload 之類的第三方依賴。然而,該支持太過單純,所以還要多做點事情,以便能更有效地進行工作。我將在本文中介紹兩個輔助方法。 閱讀全文
用接口實現回調 |
Implementing Callback with Interface |
C 語言里的函數指針,JavaScript 里的函數參數可以實現回調,從而完成很多動態功能。請看下面的 JavaScript 代碼: |
C's function pointer and JavaScript's function parameter can implement callback, accomplishing lots of dynamic functionalities. Please look at the following JavaScript code: |
- function add(a, b) {
- return a + b;
- }
-
- function sub(a, b) {
- return a - b;
- }
-
- function cal(a, b, callback) {
- alert(callback(a, b));
- }
-
- cal(2, 1, add);
- cal(2, 1, sub);
- cal(2, 1, function (a, b) {
- return a * b;
- });
|
在對 cal 函數的三次調用中,變量 callback 分別指向三個函數(包括一個匿名函數),從而在運行時產生不同的邏輯。如果仔細研究網上各種開源的 JS 庫,會發現大量此類回調。 |
In the three invokings to function cal, variable callback points to three different functions (including one anonymous function), which generates different logics at runtime. If you study various open source JS libraries on the Internet in depth, you will find many callbacks of this kind. |
Java 語言本身不支持指針,所以無法像 JavaScript 那樣將方法名直接作為參數傳遞。但是利用接口,完全可以達到相同效果: |
Java language itself doesn't support pointer, so the method name can't be directly passed as a parameter like JavaScript. But with interface, the completely same effect can be achieved: |
- public interface Cal {
-
- public int cal(int a, int b);
-
- }
-
- public class Add implements Cal {
-
- public int cal(int a, int b) {
- return a + b;
- }
-
- }
-
- public class Sub implements Cal {
-
- public int cal(int a, int b) {
- return a - b;
- }
-
- }
-
- public class Test {
-
- public static void main(String[] args) {
- test(2, 1, new Add());
- test(2, 1, new Sub());
- test(2, 1, new Cal() {
- public int cal(int a, int b) {
- return a * b;
- }
- });
- }
-
- private static void test(a, b, Cal c) {
- System.out.println(c.cal(a, b));
- }
-
- }
|
C 庫函數 feof(FILE*) 判斷文件末尾的問題 |
A Problem on Using C Library Function feof(FILE*) to Judge The End of A File |
我用 C 寫了一個程序讀取 32768 字節大小的文件,每次讀 16 個字節,應該是 2048 次讀完。但結果讀了 2049 次,并且最后兩次的數據相同,似乎重復讀取了最后 16 個字節。源代碼如下: |
I wrote a program with C, which read a file of 32768 bytes, 16 bytes each time, and it should finish reading after 2048 times. But the reault was it read 2049 times, and the data of last two times are the same, which seemed the last 16 bytes were read twice. Here is the code: |
- int loop = 0;
- while (!feof(file)) {
- loop++;
- fread(buffer, 16, 1, file);
- ......
- }
- printf("%d\n", loop); // 2049
|
我看了一陣,發現導致這個錯誤的原因是 feof(FILE*) 判斷文件末尾的機制:文件指針在文件末尾的時候,除非再讀一次導致發生 I/O 錯誤,feof(FILE*) 依然返回 0。因此用 feof(FILE*) 作為判斷條件的 while 循環始終會多讀一次,而最后一次的讀取是失敗的,buffer 也就沒有改變,看起來就像是重復讀了一次。 |
I reviewed it for a whil and found the reason that produced this error is the mechanism feof(FILE*) used to judge the end of a file: When the file pointer is at the end of a file, feof(FILE*) still returns 0 unless reads one more time to course a I/O error. Therefore, a while loop using feof(FILE*) as the judgment condition always reads one more time, and the last time of reading will fail, so buffer stayed unchanged which looked like it repeated reading once. |
用下面的代碼就沒問題了: |
Use the code below to solve this problem: |
- int loop = 0;
- while (fread(buffer, 16, 1, file) == 1) {
- loop++;
- ......
- }
- printf("%d\n", loop); // 2048
|
Java 中對象引用的類型 |
Object Reference Types in Java |
弱引用早有耳聞,但從來沒去認真看過。前天改編陳維雷先生的下雪動畫時,發現他使用了弱引用,于是趁機把 Java 的對象引用類型看了個究竟。 |
I've heard of weak reference for a long time, but have never study it seriously yet. The day before yesterday, when I was modifying Mr. William Chen's snowing animation, I saw weak reference was utilized, and then took the chance to read the details of Java's reference type. |
除了通常意義下的強引用,包 java.lang.ref 還定義了其他三種平時不太用到的引用:軟引用、弱引用和虛引用,但 API 文檔的解釋比較含糊。我在網上搜到了一些資料,簡單歸納一下。 |
Except the strong reference of common purpose, package java.lang.ref defines three other references which are less often used: soft reference, weak reference and phantom reference, but they have obscure explanations in the API documention. I searched online and got some stuffs and here are my summaries. |
強引用。當一個對象具有強引用時,Java 虛擬機寧愿拋出 OutOfMemeryError,也絕不讓垃圾回收器回收它。 |
Strong Reference. When an object holds strong references, Java Virtue Machine would rather throw an OutOfMemeryError than let garbage collector (GC) collect it. |
軟引用。當一個對象只具有軟引用時,垃圾回收器只在內存不足的時候才回收它。 |
Soft Reference. When an object holds only soft references, GC collects it only if there is not enough memory. |
弱引用。當一個對象只具有弱引用時,一旦被垃圾回收器發現就會被回收。因為垃圾回收器是一個優先級很低的線程,所以弱引用對象也不一定會馬上就會被回收。 |
Weak Reference. When an object holds only weak references, GC collects it as soon as finds it. GC is a thread of very low priority, so a weak reference object may not be collected immediately. |
虛引用。虛引用和對象的生命周期無關。虛引用必須和引用隊列聯合使用,對象將被回收前,其虛引用將被加入到引用隊列。虛引用只是用來監視對象的回收。 |
Phantom Reference. Phantom reference has nothing to do with the life cycle of an object. Phantom reference must be used together with reference queue, and the object's phantom reference will be added into that reference queue right before collected. Phantom reference is only used to monitor object collecting. |
從以上是否能看出,一個對象不能同時具有軟引用和弱引用? |
From above shall we say that an object can't have a soft reference and a weak reference at the same time? |
JDK 源代碼中的搞笑之處 |
Funny Things in JDK Source |
雖然完整版的 JDK 源代碼現已開放了,但安裝在 Java\jdk[版本號] 目錄下的公共 src.zip 仍然是我最經常參考的資源。每次我遇到一個 API 問題,都會刊這個公共源代碼。解決問題之余,我還找到很多有趣的東西,有時還搞笑。這里距三個例子。 |
Though the full version of JDK source is available now, but the public src.zip installed under Java\jdk[version_number] directory is still my most frequent refered resource. Every time I encounter an API problem, this public source is read. And besides solving those problems, I've also found many interesting things which are sometimes also funny. Here are three exaples. |
大概從 JDK 5.0 開始,類 java.lang.Object 引入了一個叫 wait(long timeout, int nanos) 的方法。等等,nanos,納秒?眾所周知,即使在強大的 Windows 多媒體 API 里面,計時器的精度也只有一毫秒,也就是一兆納秒。盡管 Java 非常棒,但不能處理納秒。而源代碼證明了這一點,納秒被舍入到最接近的毫秒,0 或 1……精彩…… |
Maybe since JDK 5.0, a method called wait(long timeout, int nanos)is introduced into Class java.lang.Object.Object. Wait a minute, nanos, is it nanoseconds? It's no secret thst even in powerful Windows multimedia API, the precision of timer is only one millisecond, that is a million nanosecond. Though Java is pretty great, it can not deal with nanoseconds. And the source proves it, that nanoseconds are rounded to the nearest millisecond, 0 or 1... Amazing... |
今天我想得到一個 JDialog 的所有者,但卻沒有 getOwner() 方法。最后我才明白 JDialog 的所有者就是它的父組件,用 getParent() 就可以了。那現在所有者等同于父級了? |
Today I wanted to get a JDialog's owner, but there's no method called getOwner(). Finally I was awear that the owner of a JDialog is exactly its parent component, and just using getParent() is okey. So owner is synonymous with parent now? |
最后,我想提下 JSpinner 的實現有錯。一些安裝在 JSpinner 上的偵聽器絲毫不起作用。我在 JSpinner.java 里找到這段注釋:“還是不對,我們沒其他辦法了,SpinnerModel 和 JFormattedTextField 現已不同步了。”JDK 的開發者的誠實值得感謝。我的解決方法是直接操控復合式組件 JSpinner 中的 JFormattedTextField。 |
At last, I wanna mention the JSpinner implementation is bugged. Some kinds of listener installed on a JSpinner take no effect at all. I found this comment in JSpinner.java: "Still bogus, nothing else we can do, the SpinnerModel and JFormattedTextField are now out of sync." The JDK developers deserve a thank for honesty. My solution is to directly manipulate the JFormattedTextField within JSpinner, a compound JComponent. |
|