原文地址:http://bobcat.webappcabaret.net/javachina/faq/01.htm
小弟自娱自乐,翻译的有些地方有些牵强,请大家帮忙校对,提出问题。如果有考SCJP的兄弟,可以帮忙校队,或一起翻译后面的几篇,既学了Java,又对英语有点帮助.
SCJP Questions & Answers by Roseanne Zhang (1)
这个FAQ是我由Marcus Green's site 和其他一些网站上的发贴收集整理成的。在回答了一些问题之后我发现,很多问题都不断地被重新提起。这是因为不同的人处于SCJP考试复习中的不同阶段,而且每天都有新人不断加入。
我的目的是让人们有地方可以找到这些答案,人们不需要再一次又一次重复回答同样的问题。我并不想覆盖有关SCJP的所有疑难,就让JCHQ去做那个吧,这个FAQs会有点难度,当然并不是所有都这样。
软件的可用性是非常重要的,分析、设计、编程都是被发明来做这个的,也是软件的基本构成。设计模式是用来重用其他设计思想的。本页面是用来重用我自己的答案的。希望这些资料能让你学得更加容易。
我们一起来创造不一样的世界吧!
新手问题
- Java是在印尼的一个美丽小岛。参看: Java, Indonesia
- Java是一种咖啡的名字。
- Java是Sun的程序员在喝了太多咖啡之后发明的一种程序语言。
他曾经叫 Oak, 但是这个商标被另外一家公司注册了,所以就改叫Java了,参看: Sun's official history
通过了programmer考试只是一个入门,别人会认为你至少知道什么是Java,会编译Java程序,也许更多。
如果你没在你的工作中用过Java写代码,通过了证明了你能用Java写代码。这个能力是比现实工作经验次一等的。如果没有任何Java或其他语言的编写经验,而要跳过developer考试直接考取Architect,我认为那是疯狂的!!!
如果你用Java编过代码,直接去准备Architect考试,那会更合理。无论如何,SCEA价值还是颇高的,可以直接考取SCEA而不一定要先考取SCJP。
为什么大部分人直接跳过developer考试而直接考SCJA(旧考试体系中的)?就是因为就是因为原来的SCJA就像SCJP都是一些选择题,相对容易过一些,还有一个原因,就是题库的外泄导致他更简单。
这也许是为什么Sun把SCJA改成SCEA.
我们有个SCJD Study Group. 如果你通过了SCJP,欢迎加入SCJD.
我的建议是别买任何考试软件,恕我直言他们都没什么大用。
但你至少得有一本书,Bill Brogden的备考书籍是第一选择.(PS:Bill没有付我广告费).找一本免费版本的Bruise Eckle的《Java编程思想》,如果你有钱的话,最好买一本(他也没付我广告费)。还有,学会用Sun的在线 "The Java Tutorial" ,这的很多问题都可以通过简单的搜索Sun的这个免费教程获得答案。
当做一些免费的或收费的测试卷的时候,把你不懂的真正搞懂。你不是只为考试而准备的,而是为了你未来的面试、工作。读书,然后一直写代码,code,code,code,知道Java真正变成你的。
当你真正受阻的时候,把你的问题发到网上来,寻求别人的解答。
当你在考试的时候碰到不明确的问题时,做个记号,然后尽力猜,先完成考试。如果你有时间,再回来做这个问题,可能就很明了了。
千万记得做标记,要不到最后你会忘记哪些是有疑问的,我就丢过好几分,因为没对一开始不懂的做记号,等后来想在回来该考虑的时候,已经忘记哪些是有疑问的。
仔细阅读题目,不要直接解答。只要把问的问题正确解答就可以了,不要写一些无关的,有些问题会有一系列提示词让你挑选。
别画蛇添足。
- General: http://suned.sun.com/USA/certification/javamain.html
- SCJP: http://suned.sun.com/USA/certification/progdetails.html
- SCJD: http://suned.sun.com/USA/certification/devdetails.html
- SCJEA: http://suned.sun.com/USA/certification/archdetails.html
语言基础
关键字是预定义字,而预定义字不是关键字。详细参看:Java Language Keywords
在java和c++中,this是一个用来指向当前所在的自我对象的指针。
官方建议的mian方法是:public static void main(String[] args){}
你必须把他记住,在SCJP考试中可能会用到的。
但是,如果你不写public甚至用private代替public,一些JVM或许会让你的Java程序不出错通过编译,为什么?
因为一些JVM会让他们容忍他们能容忍的一些错误。像这种事在M$的世界中是经常出现的。我猜Sun从他们那学到了这个,看看2001年他们的股票价格,你就会知道为什么了。
In the following example, four test() methods, if we pass ambiguous /b{null} to the test, which one should (will) be called? The 3 on top has super/subclass/sub-subclass relationship. The most specific one (down hierarchy) will be called. The 4th with String as a parameter, but it is a sibling of Tester. Ambiguity compile time error results.
在下面的这个例子中,有四个test()方法,如果我们传一个不明确的参数到test,那么那个会被执行?
最上面那三个依次是父类,子类,子类的子类的关系.定义最详细的那个将会被执行(也就是子类的子类).第四个test用String做参数,但和Tester是一个层次的,如果去掉第四个test的注释,那么就会出现编译期的二义性错误.
class Tester { void test(Object s) { System.out.println ("Object version"); } void test(Tester s) { System.out.println ("Tester version"); } void test(SubTester s) { System.out.println ("SubTester version"); } // Not compilable any more if you uncomment the line // since String and Tester are siblings // void test(String s) { System.out.println ("String version"); } public static void main (String args[]) { Tester c = new Tester (); // Ambiguous, the most specific one which fit will be call c.test (null); // SubTester version c.test (new Object()); // Object version } } class SubTester extends Tester{ }
public class Test { // lbla: //compilable Error: identifier expected public static void main(String[] args) { // lblb: //compilable Error: A declaration cannot be labeled Object o = new Object(); int n = 1; lblc: if (o instanceof Object) { while (true) { n++; if (n > 5) break lblc; System.out.println(n); } } System.out.println("Finished n"); lblx: for (int i = 3; i < 7; i++){ // skip number 5 if (i==5) continue lblx; System.out.println(i); } lbly: // legal before another lable lblz: { System.out.println("Watch:"); break lbly; // compilable Error: statement not reached //System.out.println("This will never be printed out."); } } }
Quote from Java 2 : The Complete Reference by Patrick Naughton, Herbert Schildt, Herb Schildt Pg. 147:
Constructors look a little strange because they have no return type, not even void. This is because the implicit return type of a class' constructor is the class type itself构造函数看起来有点奇怪,因为他没有返回类型,甚至不是void,因为一个类的构造函数肯定是这个类本身的类型。
MyObj o = new MyObj();
![](JavaChina%20SCJP%20Questions%20&%20Answers%20by%20Roseanne%20Zhang%20%281a%29.files/S.gif)
Q. What is the difference of null in Java and NULL in C++?
// 猜猜这个程序输出什么,然后运行看看结果. // A good IQ test public class A { public static void main(String args[]) { int x = 0; while (x < 10) { System.out.print(" " + x); switch (x) { case 5: x += 2; continue; case 2: break; case 7: break; default: x++; }; x++; } } }
Keep It Simple and Stupid (KISS). Please!
如果你坚持要那样的话,那就试试看.
![](JavaChina%20SCJP%20Questions%20&%20Answers%20by%20Roseanne%20Zhang%20%281a%29.files/S.gif)
Q. How to create my own package, how to call my class in another package?
对于没有public类的java文件,其文件名的命名没有任何限制.如果有一个带main()的类,你可以考虑把文件名命名为这个类名.你最好按你的习惯命名,当然这些都不是强制的.做一下下面这个实验:
// D.java class A {} class B {} class C {} class E { public static void main(String[] args) { System.out.println("Strange thing in E."); } } class F { public static void main(String[] args) { System.out.println("Strange thing in F."); } }
java E //output: Strange thing in E.
java F //output: Strange thing in F.
如果你仔细想想,会明白的.(译者注:每个类在编译的时候被单独编译成一个类名.class的文件,无论他们在不在一个文件)
在接口中所描述的所有东西都是显式public或隐式public,如果你定义的时候不说明是什么类型的,他们都是public而不是default,在接口总不能有非public存在,大家想想接口用途就知道了。
如果为理论研究,这有一个有趣的站点,叫 Lykkenborg eZine. 作者想尽量让Java的语法更容易掌握.
Java的基本类型和类型转换
下面这个二进制如果代表两种类型的话,其值应该是:
1111 1111 1111 0100 Signed : -12 unsigned: 65524 0000 0000 0000 1100 Signed : 12 unsigned: 12如果你不知道负数怎么出来的,看看这篇文章 Two's complement.
在java里,只有char是无符号的,其他像byte,short,int,long都是有符号的,像c/c++这些语言,除了char总是无符号的,其他类型总是有个unsigned brother.
0 to 65535
0 to 1111 1111 1111 1111
'/u0000' to '/uFFFF'
上面的都是相等的,因为char是无符号的2字节整数.
用你的科学计算器来算算第一个到第三个的转换,你也可以这样认为:
1111 1111 1111 1111 + 1 = 1 0000 0000 0000 0000 = 2 16
![](JavaChina%20SCJP%20Questions%20&%20Answers%20by%20Roseanne%20Zhang%20%281a%29.files/S.gif)
eg. long l=12345678; float f = l; // ok to compiler
Primitive Data Types
类型 | 位数 | 范围 | 默认值 | |
---|---|---|---|---|
Boolean | 8, 1 bit used | true | false | false |
char | 16 | '/u0000' | '/uFFFF' | '/u0000' |
byte | 8 | -128 | +127 | 0 |
short | 16 | -32,768 | +32,767 | 0 |
int | 32 | -2,147,483,648 | +2,147,483,647 | 0 |
long | 64 | -9,223,372,036,854,775,808 | +9,223,372,036,854,775,807 | 0 |
float | 32 | -3.40292347E+38 | +3.40292347E+38 | 0.0 |
double | 64 | -1.79769313486231570E+308 | + 1.79769313486231570E+308 | 0.0 |
当给整型(无论有无符号)分配内存的时候,编译器会检查这些值有没有超过此类型所能表达的范围,如果不超的话就编译通过,否则出错.
float f = 1.3; float f = 1.3f; double d = 1.3;
1.3d和1.3f的区别在于其精度不同,而非范围.当给浮点点数分配内存的时候,也是因此才产生问题的.1.3默认是doule精度的,将他赋给一个float类型会损失精度.他需要类型转换.
因为精度所代表的涵义,1.3和1.30在物理/数学领域是不同的.
距离1.3英里意味着是在1.25英里和1.35英里之间。
距离1.30英里意味着是在1.295英里和1.305之间,这样表示更精确.
当然不是每个人都这样认为.
class My{ static long l; static float f; static char c; static byte b; public static void main(String[] ss) { b=c; //not compilable c=b; //not compilable either l=f; //not compilable f=l; //OK } }
float转换成long则更显然了,因为小数部分会丢失。
因为boolean只有两个值(true,false),一位就绝对够存储了。但是,在内存中我们没法得到每一位的地址,而我们又没法使用一个byte(8位),换句话说,我们只用了1位,空了7位没用。
为证明这个理论,运行这个程序TestBoolSerialize.java. 输出文件Bool.tmp和Byte.tmp将会是同样大小,但是Short大小是他们的两倍。
如果你内存用光了,可能你只能运行到一半就死了?
不要太担心这个,Java会把内部表示处理得很漂亮的,程序员不需要像c/C++那样主动申请/释放内存。还记得在C/C++中进行指针操作的时候,老会用到sizeof()?Java里没有sizeof(),我上面那个程序用了sizeof()的小技巧来向你揭示Java的密码。To the top
long l = 300L; int i = (int)l; // cast a long to an int class A {} class B extends A {} // will compile and run fine A a = new B(); B b = (B)a; // cast A reference a to a B reference b // runtime fine since a is actually a B // will compile fine and ClassCastException will be thrown on runtime A a = new A(); B b = (B)a; // cast A reference a to a B reference b // runtime exception will be thrown since a is not really a B //运行时会出错,因为a并不真的是B类型。
- 由子类向父类的向上转换是没必要转换,因为以为按照关系,橡树就是树。
- 不要把父类转换成子类,虽然在编译的时候会忽略错误,但如果你把树转换成橡树,他有可能是对的,但你保证不了,也许某颗书是苹果树呢。在这种情况下, ClassCastException 错误将会在运行期被抛出。
- 如果你转换同一层次的子类,甚至毫无关系的子类,就会出现编译期错误,因为编译期已经掌握了这些类的类型信息。比如,你把橡树转换成苹果树,甚至家具,就会出现编译错误。
- 可是,当你进行接口之间的转换的时候,甚至两者是毫无关系的,编译器也不会报错。
Base b=new Base(); Sub s=new Sub(); //Sub extends Base s=(Sub)b;
"Chinese is not necessary an oversea Chinese, but possible."(“华人不必是华人,只是可能”)
When you cast super to sub, compiler assume that you know what you were doing, since it is possible. However, runtime will find out b actually is not a Sub.当你把父类转换成子类,编译器认为你知道你在干什么,因为进行这种转换是可能的。可是,运行时将会发现b却不是子类(而是父类)
尽管猫是动物,但动物不一定是猫,但也有可能是猫。
这就是为什么向下转换在编译的时候能通过,因为编译器认为你知道你正在干什么,但是,运行时就会发现这只动物事实上不是猫。
ClassCastException! Big time.
- 在电脑中所有东西都是用0或1代表,每8位构成一个byte,这就是为什么所有东西都能用byte流读取。
- byte是内存单元地址的最小单位。
- 解释这些应该是操作系统和软件课程的事。
- 作为Java的基本类型,char是16位无符号整型,byte是8位带符号整型,short是16位带符号整型。
- char和short的区别就在于第一位所代表的意思。
class Test { public static void main(String[] args) { Test t = new Test(); t.test(1.0, 2L, 3); } void test(double a, double b, short c) { System.out.println("1"); } void test(float a, byte b, byte c) { System.out.println("2"); } void test(double a, double b, double c) { System.out.println("3"); } void test(int a, long b, int c) { System.out.println("4"); } void test(long a, long b, long c) { System.out.println("5"); } void test(float a, long b, int c) { System.out.println("6"); } } // output: 3 // think why?
- 3 (整型)在Java里面默认是int类型.
- 1.0 (浮点型) 在Java里面默认是double类型.
- 错!因为3是int,int到short需要显式转换.
- 错!三个参数都匹配错误.
- 对!因为第二、第三个参数可以向上转换成double.
- 错!因为1.0是double类型,double到int需要显式转换.
- 错! double到long需要显式转换.
- 错!double到float需要显式转换.
Copyright ? 1999 - 2005 Roseanne Zhang, All Rights Reserved
[ JavaChina] [ Online Tutoring, Training] [ SCJD Group]