26 // 方法名一并传给其内部调用处理器对象的invoke方法,并调用该方法(invoke).
27 //4. 这里Proxy子类会将所有实例化时指定接口(Comparable)的方法(compareTo),以及
28 // Object中toString、equals和hashCode方法的调用都会传递给调用处理器的invoke方法。
29 //5. 因此在输出结果中不仅可以看到compareTo方法的调用被打印出,toString也可打印。
30 int result = Arrays.binarySearch(elements, key);
31 if (result >= 0)
32 System.out.println(elements[result]);
33 }
34 }
35
36 class TraceHandler implements InvocationHandler {
37 //由于Proxy的子类是动态生成的,其具体的实现也是编译器动态生成后传给JVM的。
38 //因此这里是整个代理机制中唯一存放被代理对象的地方。
39 public TraceHandler(Object t) {
40 target = t;
41 }
42
43 //在此例中,该方法是被Comparable接口中的compareTo方法调用的,该实现逻辑是位于该
44 //动态生成的Proxy子类中,如
45 //public MyProxy extends Proxy implements Comparable {
46 // int compareTo(Object other) { h.invoke(...); }
47 @Override
48 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
49 //打印出实际被调用方法的名称和参数值。
50 System.out.print(target);
51 System.out.print("." + method.getName() + "(");
52 if (args != null) {
53 for (int i = 0; i < args.length; ++i) {
54 System.out.print(args[i]);
55 if (i < args.length - 1)
56 System.out.print(", ");
57 }
58 }
60 //交给被代理类做实际的比较。
61 return method.invoke(target, args);
62 }
63 private Object target = null;
64 }
65 /* 输出结果如下:
66 500.compareTo(128)
67 250.compareTo(128)
68 125.compareTo(128)
69 187.compareTo(128)
70 156.compareTo(128)
71 140.compareTo(128)
72 132.compareTo(128)
73 128.compareTo(128)
74 128.toString()
75 128 */
七、异常和断言:
1. 异常处理:
1) 异常规范表示对于"已检查"(checked)异常,如FileNotFoundException等,既在程序运行期间可以预测到的逻辑问题引发的异常,对于该类异常,需要在包含该异常的函数声明部分标识出来,该函数可能会引发此类异常,如:
public Image loadImage(String s) throws IOException, MalformedURLException
如果在loadImage中仍然存在其他"已检查",但是没有在函数的异常规范中声明出来,那么将会导致编译失败,因此对于函数中所有"已检查"必须按照Java异常规范的要求,在函数的声明中予以标识。对于该函数(loadImage)的调用者而言,在调用该函数时,必须将其放入try块中,同时在catch字句中捕捉异常规范中标识的异常或他们的超类。
对于"运行时异常"(unchecked or runtime),由于大多是程序Bug或JVM问题所致,因此不可预测性极强,如ArrayIndexOutOfBoundException,对于该类异常无需在函数的异常规范部分予以声明。
在C++标准中也同样存在异常规范的说法,如
File* loadFile(const char* s) throw std::bad_error
所不同的是C++没有明确的要求如果函数内部抛出了该异常,则必须在函数声明的异常规范部分予以声明,对于函数调用者而言也同样没有这样的规定,必须捕获其中的异常,因此异常规范在目前的C++编译器中只是一种提示性的声明。Java和C++在异常规范方面还存在的另一个区别是,C++中,如果函数没有throw字句,那么该函数仍然可以抛出任何异常,但是对于Java的"已检查"(checked)异常则必须通过throws字句声明。
2) 如何抛出异常,在此方面,Java和C++没有太大的差异,唯一的不同是Java抛出的异常必须是Throwable的实现类,C++中则没有这样的限制,也不存在这样的异常接口。见如下代码:
1 public void howToThrowException() {
2 if (someErrorOccurred)
3 //1. 通过throw关键字直接抛出指定异常类型的对象即可。
4 throw new MyCheckedException();
5 }
3) 异常捕捉:由于Java中所有的异常均继承自Throwable,所以catch(Throwable e)可以捕捉所有类型的异常,无论该异常是否为checked or unchecked异常,但是C++中并不存在这样的异常祖先接口,因此如果想达到这样的效果需要使用catch(...)关键字,这同样表示捕捉所有的异常。
4)