Tuesday, December 26, 2006

12月25日考SCJP

86%过了SCJP(310-055 English),只看了两天的书,但受益非浅,第一次知道Java还有这么多有趣的行为。

  • Declarations,Initialization and Scoping 83%
  • Flow Control 90%
  • API Contents 90%
  • Concurrency 75%
  • OO Concepts 90%
  • Collections/Generics 70%
  • Fundamentals 100%


1 Override:
一个完整的方法包括 修饰符 + 返回类型 + 方法标识 + 参数 + 异常声明 + 方法体。
构造方法默认返回类型是他自己,所以不用声明。但如下的代码依然是可以通过的:


public class Test{
public Test(){} //构造器
public int Test(){return 1;} //普通的方法
public Test Test(){return this;} //普通的方法
}

对于重写(Override),子类与父类的 方法标识、参数 必须相同。

  • 修饰符:子类无法缩小父类 方法的访问权限。
  • 返回类型:子类无法扩大父类的返回类型。
  • 可以不声明父类已经声明的异常、可以再添加新的异常声明、不能声明父类声明的异常的父类。
  • 方法体内可以随意使用super.method()和this.method()。对于构造器,super()和this()中最多有一个调用一次,且须在方法体第一行。
  • 方法调用类似与C++的virtual(陈胖子的指点),Super b=new Sub(); b.method()调用的是Sub的方法,而 b.var 是父类的字段。
  • 对象的实例化是依次从最顶层的父类开始构造。

关于构造,可以这样理解:

public class A{int a=0;Object a(){}}
public class B extends A{int a=1;String a(){}}

B b=new B();时堆栈情况如下:
A -> int a -> 0
Object a() -> B.a()的地址(因为重写只允许虚方法重写)
B -> int a -> 1
String a() -> B.a()的地址

有一道很狡猾的题目:

class SuperBase{
void p(SuperBase a){
System.out.println("super");
}
}

class Base extends SuperBase{
void p(Base a){
System.out.println("base");
}
}

class Derived extends Base{
static void p(Derived a){
System.out.println("derived");
}
}

public class Test{
public static void main(String[] ag){
SuperBase a1=new SuperBase();
SuperBase b1=new Base();
Base c1=new Derived();
a1.p(new Base());
b1.p(new Derived());
c1.p(new Derived());
}
}

输出结果是supersuperbase,首先要注意都不是重写而是重载。而b1.p结果是super是因为用SuperBase声明的b1只有一个方法 指针p(SuperBase),所以输出super。

2 equals:
5之后有了autoboxing/unboxing,所以要特别注意

Integer a=new Integer(0);
Integer b=new Integer(0);
int c=0;

a==b is false //未拆箱比较
a==c is true //拆箱后比较
c.equals(b) //编译错误
b.equals(c) //true

String的原理与boxing是不同的,理解带引号的字符串会存放在一个优化了的缓冲池里,而用String构造出来的则是实际的对象,其实和其他基 本类型相似,唯一的不同就是不是通过装箱和拆箱来实现两者之间的转换。所以:

String a="a";
String b=new String("a");
Stringc=new String("a");

a==b is false
a=="a" is true
b==c is false

equals是Object的方法,默认实现方法是比较对象地址,为了保持和hashCode()一致,最好重写。

StringBuilder a=new StringBuilder("abc");
StringBuilder b=new StringBuilder("abc");
a.equals(b) is false //StringBuilder没有重写equals,所以用默认的地址比较
如果 a.equals(b)是true,那么a.hashCode()==b.hashCode()一定是true。
如果a.hashCode()==b.hashCode()是true,a.equals(b)不一定是true!

关于boxing,switch语法中的case 是不能自动拆箱的:

switch(0){
case 0: //正确
case new Integer(1): //错误!
case 1+1: //正确
}

还有,System.out.printf("%f",123)是错误的,因为%f对应的是integer 123,不能隐式转型。

3 Generic:
5出来以后Generic一直是比较难搞懂的。

ArrayList<A> list=new ArrayList<B>(); //无论AB什么关系,都是不行的
List<A> list=new ArrayList<A>(); //ok
List<?> list=new ArrayList<A>(); //无论A是什么类型,都可以
List list=new ArrayList<A>(); //ok

List<?> list=new ArrayList<A>();
ArrayList<B> blist=(ArrayList<B>)list; //带warning,编译可以通过

泛型不能作为instanceof的操作值。
ArrayList<Integer> a=new ArrayList<Integer>();
a instanceof ArrayList //true
a instanceof ArrayList<?> //true
a instanceof ArrayList<Integer> //Compile Error
4 Serialize:
  • 继承Serializable的类在Deserialize时不调用构造方法,其父类(没继承Serializable)则一定要调用构造器。
  • 含未Serializable的字段,在串行化时会抛异常,不是Compile Error。


5 罕见的关键字:
保留的:goto,const
transient:串行化时不串行的变量
volatile:易变的变量,多线程时不会有拷贝
strictfp:保持在不同平台上的精度运算结果相同

6 Thread:
用于线程阻塞的方法有sleep()和wait()/notify()两种,其中wait()要放在synchronized段内,以保证监视器正在监控该线程。


synchronized (Thread.currentThread()){ // <-修改为其他实例就不抛异常
obj.wait(); //抛出异常IllegalMonitorStateException
}


7 函数参数:
无法同时声明 void a(String... b) 和 void a(String[] b)
可以同时声明 void a(String b,String... c) 和 void a(String... c),编译通过。但无法调用,因为会有二义性。


8 真题回忆:

感觉自己应该9*%过的(也许考完试的人都有这种心理吧,呵呵),回顾几道题:

-------------------------------------------------------------------------------



public class Main{
public static void main(String[] ars){
// code 1
try{
// code 2
}catch(Exception e){
// code 3
}finally{
System.out.println("a");
}
}
}

问以下五种情况中选三种,使一定会打印出a来:

A 当开始调用垃圾回收时
B 在code 1 抛异常
C 在code 2 抛异常
D 在code 3 抛异常
E code 1 处代码顺利执行

考试时我确定的是 CE,对于B和D我觉着是等价的(因为我一直牢记finally是无论如何都会执行到的)。

回来试了代码才知道,情况B抛出异常后就不会执行finally段!
-------------------------------------------------------------------------------


import java.util.*;
public class Main{
public static void main(String[] ars)throws Exception{
List<String> list=new ArrayList<String>();
list.add("b");
list.add("a");
list.add("c");
System.out.println(Collections.binarySearch(list,"a"));
}
}

问输出: A 0 B 1 C 2 D "a" E "b" F "c"

我选择的是D,因为确实没怎么用过binarySearch,结果是B。

-------------------------------------------------------------------------------
有一道生产者与消费者的问题:


boolean flag=false;
public synchronized void produce(){
flag=true;
___1____
}
public synchronized void comsume(){
while(!flag){
____2____
}
flag=___3___ ;
}

具体选项已经忘记了,因为实在不能确定这题的解,所以凭经验随便填的,我填的是 1 notifyAll() 2 wait() 3 false。
-------------------------------------------------------------------------------
有一道关于Scope的题目,题意不是很懂:



package test;
public class A{
public B instance=new B();
class B{
public int a;
}
}

问以下哪个关于a的access选项是正确的

A any class
B none class
C classes only in package test
D classes only in class A

我当时选择C,考虑到B是包级私有的,所以只能由test包下的类访问。结果~ 答案是A,测试得所有类都可以访问。
-------------------------------------------------------------------------------
还有一道命令行下access的问题,问某人忘记Chess.class放在那里了,运行以下命令后可启动Chess,那么Chess.class可能的位置是哪个?(unix下)

java -classpath test:/home/opt/*.jar game.Chess

n多乱七八糟的选项,我只记得两个,因为我在他们之间徘徊了许久:

A test/game/Chess.class
B /home/opt/chess.jar包内 (保证manifest正确)

我选择的是A,但试了一下都可以,郁闷。
-------------------------------------------------------------------------------

经沈(胖子?呵呵)提醒,又想起一道Thread的题目:



public class T extends Thread{
public void run(){
try{
Thread.sleep(1000);
}catch(InterruptedException e){
System.out.println("Interruptted");
}
System.out.println("done");
}
public static void main(String[] args)throws Exception{
System.out.println("start");
T th=new T();
th.start();
th.sleep(2000);
System.out.println("gogo");
th.interrupted();
System.out.println("finished");
}
}

问输出,我给的答案是 start->gogo->Interruptted->done->finished。运行了一下程序得:start->done->gogo->finished。仔细想想,原来th.sleep(2000)是个骗局,sleep的是main线程,上当了。

陈胖子(应胖昕要求这么叫他)很可惜,55% 就差了三题。不过他算是很厉害的了,因为两天之前他还是从没用过Java的人!应该让他考310-035的,这样就能过了。希望他把悲痛都随着那顿麦当劳吃下肚子,再接再历!

2 comments:

Sumhat said...

Congradulations.....

binarySearch("a")如果返回"a"貌似是多此一举=.=

1.5的题目分类貌似和1.4有很大差异,1.4里有GC和Thread的.

陈胖子有点急了,用都没用过.....

Ray said...

GC算在Fundamentals里了吧,Thread在Concurrency里有考到,见我补充了一道题。
陈胖子冲动了,不过还是满猛的。