继续学习McGraw.Hill.OCP.Java.SE.6.Programmer.Practice.Exams,开始第二套自测题。

1. 问下面这段程序的输出结果?

public class VLA2 implements Comparator<VLA2> {
    int dishSize;

    public static void main(String[] args) {
        VLA2[] va = { new VLA2(40), new VLA2(200), new VLA2(60) };

        Arrays.sort(va, va[0]);
        int index = Arrays.binarySearch(va, new VLA2(40), va[0]);
        System.out.print(index + " ");
        index = Arrays.binarySearch(va, new VLA2(80), va[0]);
        System.out.print(index);
    }

    public int compare(VLA2 a, VLA2 b) {
        return b.dishSize - a.dishSize;
    }

    VLA2(int d) {
        dishSize = d;
    }
}

A. 0 -2
B. 0 -3
C. 2 -1
D. 2 -2
E. Compilation fails.
F. An exception is thrown at runtime.

这题考对Arrays API的熟悉度。

sort(T[] a, Comparator<? super T> c)
          Sorts the specified array of objects according to the order induced by the specified comparator.

按照指定的比较器进行排序。这里是根据 dishSize 来比较大小,降序排列。更多可以参考这篇博文http://develop.csai.cn/java/200905260937361763.htm

binarySearch(T[] a, T key, Comparator<? super T> c)
          Searches the specified array for the specified object using the binary search algorithm.

回顾一下二分查找法,又称折半查找。

二分查找法 Binary Search

在对线性表的操作中,经常需要查找某一个元素在线性表中的位置。此问题的输入是待查元素x和线性表L,输出为x在L中的位置或者x不在L中的信息。

比较自然的想法是一个一个地扫描L的所有元素,直到找到x为止。这种方法对于有n个元素的线性表在最坏情况下需要n次比较。一般来说,如果没有其他的附加信息,在有n个元素的线性表中查找一个元素在最坏情况下都需要n次比较。

下面我们考虑一种简单的情况。假设该线性表已经排好序了,不妨设它按照主键的递增顺序排列(即由小到大排列)。在这种情况下,我们是否有改进查找效率的可能呢?

如果线性表里只有一个元素,则只要比较这个元素和x就可以确定x是否在线性表中。因此这个问题满足分治法的第一个适用条件;同时我们注意到对于排好序的线性表L有以下性质:

比较x和L中任意一个元素L[i],若x=L[i],则x在L中的位置就是i;如果x<L[i],由于L是递增排序的,因此假如x在L中的话,x必然排在L[i]的前面,所以我们只要在L[i]的前面查找x即可;如果x>L[i],同理我们只要在L[i]的后面查找x即可。无论是在L[i]的前面还是后面查找x,其方法都和在L中查找x一样,只不过是线性表的规模缩小了。这就说明了此问题满足分治法的第二个和第三个适用条件。很显然此问题分解出的子问题相互独立,即在L[i]的前面或后面查找x是独立的子问题,因此满足分治法的第四个适用条件。

于是我们得到利用分治法在有序表中查找元素的算法。

function Binary_Search(L,a,b,x); begin if a&gt;b then return(-1) else begin m:=(a+b) div 2; if x=L[m] then return(m) else if x&gt;L[m] then return(Binary_Search(L,m+1,b,x)); else return(Binary_Search(L,a,m-1,x)); end; end;

在以上算法中,L为排好序的线性表,x为需要查找的元素,b,a分别为x的位置的上下界,即如果x在L中,则x在L[a..b]中。每次我们用L中间的元素L[m]与x比较,从而确定x的位置范围。然后递归地缩小x的范围,直到找到x。

下面分析该算法的复杂性。设在n个元素的数组中查找x需要的比较次数为T(n),如果每次比较x和L[m]时,总有x<>L[m],即x根本不在L中,则:

T(n)=2+T(n/2),T(1)=1

该方程的解为T(n)=O(logn)。所以在最坏情况下二分查找法的复杂度为O(logn)。

再来看看JDK的实现。

    public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
                       T key, Comparator<? super T> c) {
    rangeCheck(a.length, fromIndex, toIndex);
        return binarySearch0(a, fromIndex, toIndex, key, c);
    }

    // Like public version, but without range checks.
    private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
                     T key, Comparator<? super T> c) {
        if (c == null) {
            return binarySearch0(a, fromIndex, toIndex, key);
    }
    int low = fromIndex;
    int high = toIndex - 1;

    while (low <= high) {
        int mid = (low + high) >&gt;&gt; 1;
        T midVal = a[mid];
        int cmp = c.compare(midVal, key);

        if (cmp < 0)
        low = mid + 1;
        else if (cmp > 0)
        high = mid - 1;
        else
        return mid; // key found
    }
    return -(low + 1);  // key not found.
    }

到Eclipse里Debug一把你就啥都明白了。

OCP Java 自测(2)_休闲

正解:D。

2. 问下面这段程序的输出结果?

public class WeatherTest {
    static Weather w;

    public static void main(String[] args) {
        System.out.print(w.RAINY.count + " " + w.Sunny.count + " ");
    }
}

enum Weather {
    RAINY,
    Sunny;
    int count = 0;

    Weather() {
        System.out.print("c ");
        count++;
    }
}

A. c 1 c 1
B. c 1 c 2
C. c c 1 1
D. c c 1 2
E. c c 2 2
F. Compilation fails.
G. An exception is thrown at runtime.

应该把枚举变量看作实例变量而不是静态变量。

正解:C。

3. 问下面这段程序的输出结果?

public class Gazillion {

    public static void main(String[] args) throws Exception {
        String s = "123.456xyz";
        NumberFormat nf = NumberFormat.getInstance();
        System.out.println(nf.parse(s));
        nf.setMaximumFractionDigits(2);
        System.out.println(nf.format(s));
    }
}

A. Compilation fails.
B. The output will contain "123.45 "
C. The output will contain "123.456"
D. The output will contain "123.456xyz"
E. An exception will be thrown at runtime.

这题漏选了C,前半部分是可以正常解析的,后面的 xyz 才会抛出异常。

正解:CE。

OCP Java 自测(2)_OCP_02

4. 给出下面这段程序:

2. public class Internet {
3. private int y = 8;
4. public static void main(String[] args) {
5. new Internet().go();
6. }
7. void go() {
8. int x = 7;
9. TCPIP ip = new TCPIP();
10. class TCPIP {
11. void doit() { System.out.println(y + x); }
12. }
13. ip.doit();
14. }
15. }
选择所有正确选项?
A. Compilation succeeds.
B. Compilation fails due to an error on line 3.
C. Compilation fails due to an error on line 8.
D. Compilation fails due to an error on line 9.
E. Compilation fails due to an error on line 10.
F. Compilation fails due to accessing x on line 11.
G. Compilation fails due to accessing y on line 11.

考察内部类。方法内部类只能在定义该内部类的声明只有实例化,所以D是错的。方法内部类对象不能使用该内部类所在方法的非final局部变量,所以F是错误的。

正解:DF。

5. 给出下面这段程序:

4. public static void main(String[] args) {
5. try {
6. if(args.length == 0) throw new Exception();
7. }
8. catch (Exception e) {
9. System.out.print("done ");
10. doStuff(); // assume this method compiles
11. }
12. finally {
13. System.out.println("finally ");
14. }
15. }
选择所有正确选项?
A. "done "
B. "finally "
C. "done finally "
D. Compilation fails.
E. No output is produced.

漏选了A。如果没有带命令行参数,将会抛出异常,捕捉到异常后,打出”Done”,然后执行doStuff()。鬼晓得doStuff干了些什么,如果调用了System.exit(1)可不就只有一个“Done”。

正解:A、B、 C。

6. 给出下面这段程序:

public class Two {
    public static void main(String[] args) {
        int y = 0;
        assert y == 0;
        if (args.length &gt; 0) new One();
    }
}

class One {
    int x = 0;
    {
        assert x == 1;
    }
}

选择所有能正确运行的选项?
A. java Two
B. java Two x
C. java -ea Two
D. java -ea Two x
E. java -ea:One Two
F. java -ea:One Two x
G. java -ea:Two Two x

从JDK1.4开始自带断言支持。参考:http://java.sun.com/developer/technicalArticles/JavaLP/assertions/。断言默认情况下不开启,需要带上-enableassertion (-ea)参数来使用。

正解:A、B、C、E、G。
7. 给出下面这段程序:

public class BeSafe {

}

class SafeDeposit {
    private static SafeDeposit singleton;

    public static SafeDeposit getInstance(int code) {
        if (singleton == null) singleton = new SafeDeposit(code);
        return singleton;
    }

    private int code;

    private SafeDeposit(int c) {
        code = c;
    }

    int getCode() {
        return code;
    }
}

选择正确选项?
A. Compilation fails.
B. Class BeSafe can create many instances of SafeDeposit.
C. Class BeSafe CANNOT create any instances of SafeDeposit.
D. Class BeSafe can create only one instance of SafeDeposit.
E. Class BeSafe can create instances of SafeDeposit without using the getInstance() method.
F. Once class BeSafe has created an instance of SafeDeposit, it cannot change the value of the instance’s "code" variable.

在单线程场景下,只会有 SafeDeposit 的实例,但在多线程并发的时候,就有可能出现多个 SafeDeposit 实例,getInstance并没有加上同步代码块。

正解:B、F。