|
|
2008年3月10日
| 用接口实现回调 |
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));
- }
-
- }
|
2007年12月6日
| 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 个字节。源代码如下: |
Dudu 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
|
2007年12月2日
| 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? |
2007年11月30日
| 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. |
2007年11月28日
| 我对 Java 关键字 Synchronized 的新理解 |
My New Understanding of Java's Synchronized Keyword |
| 说实话,我对 Java 并发编程知之不多。我曾经常用关键字 volatile 试图“强制原子操作”,结果带来的麻烦比解决的还多。Sun Java 教程中的并发课程我以前从没看完过,现在该通读一遍了。 |
To be honest, I knew only a little about concurrent programming in Java. I uesed to use keyword volatile as an attempt to "enforce atomic operations" which had brought me more troubles than solved. Time to walk through the Concurrency Trail of Sun's Java Tutorials that I never finished reading in the past. |
| 我其实知道并经常看到关键字 synchronized 的使用,但直到昨天我还没发觉就这个字消除了很多同步问题。然而,真正的答案在我第一次看这个教程时就在里面了,到这次才弄清。 |
I do know and often see the usage of keyword synchronized, but until yesterday I hadn't figured out how thie single word elimated so many synchronization problems. However, the very answer lies in those tutorials ever since I first read it and this time it has been clearly understood. |
| 每个对象都关联有一个内部锁,也被称作监视器锁或简称监视器。当一个线程调用一个同步方法时,它自动请求此方法的内部锁,并在方法返回时释放。即使是未捕获的异常造成了返回,也会发生锁的释放。而对静态同步方法,方法所在类的 Class 对象的内部锁被请求。同步语句的内部行为没什么两样,只是还需要显示指定一个需要请求其内部锁的任意对象。 |
Every boject has an intrinsic lock, which is also known as monitor lock or monitor for short, associated with it. When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception. As for a static synchronized method, an intrinsic lock for the Class object of that method's Class is acquired instead. Synchronized statements internally behaves no differently except in addition to this, an arbitrary object whose intrinsic lock will be acquired can be and should be explicitly specified.
|
| 总之,synchronized 关键字是锁定对象的简单方式,也有很多局限。java.util.concurrency.locks 包支持更高深的锁定用法,也是我将要学的。 |
In conclusion, synchronized keyword is a simplified way of locking objects, and also has many limitations. More sophisticated locking idioms are supported by the java.util.concurrency.locks package which I am going to learn.
|
|