scjp考试认证
赋值操作符=
基本数据类型的赋值操作
boolean数据只能赋值于另一个boolean数据。不同于c和c++,java中的boolean值只能是true和false。
其它的数据类型可以自由的进行widening conversion(宽化转换)。而进行narrowing conversion(窄化转换)由于有精度的损失,必须进行强制转换。
Primitives may be assigned to "wider" data types, a boolean can only be assigned to another boolean
引用数据类型的赋值操作
引用数据类型的赋值,例如a=b,使得a和b引用指向相同的对象。引用数据类型的赋值可以向上转型。即一超类的引用可以被赋值一子类对象。但向下转型必须强制转换。
Object references can be assigned up the hierarchy from child to base.
示例: 赋值操作符
class SuperClass {
int i;
}
class Child1 extends SuperClass{
int j;
}
class Child2 extends SuperClass{
int k;
}
public class Assignment {
public static void main(String[] args) {
//primitive datatype
boolean b=false;
int i=0;
char c='e';
byte bt=0;
short s=0;
long l=12;
float f =32.0f;
double d=21.0;
// widening conversion
//i=b;
i=c;
i=bt;
i=s;
f=l;
// narrowing conversion
bt=(byte)i;
s=(short)c;
//reference datatype
SuperClass n1 = new Child1();
SuperClass n2 = new SuperClass();
SuperClass n3 = new Child2();
Child1 c1=new Child1();
Child2 c2=new Child2();
n1.i = 9;
n2.i = 47;
System.out.println("1: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1 = n2;
System.out.println("2: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1.i = 27;
System.out.println("3: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1=n3;
n1.i=4;
System.out.println("3: n1.i: " + n1.i +
", n3.i: " + n3.i);
//! c1=(Child1)c2;
}
}
++,--: 前序递增和前序递减(++a,--a)先进行运算然后才增赋值。后序递增和后序递减(a++,a--)先赋值然后才进行运算。
奇怪的++与--:
int a=1,b=5;
b+=b++-a--; (b=9)
b=b++;(b=9)
b=++b; (b=10)
关系操作符
关系操作符(<,>,<=,>=,==,!=)所产生的结果是boolean,==,!=可用于所有的内置的类型,其它运算符不能用于boolean.
奇怪的==(对于引用类型==比较两个对象的内存地址,这可不是我们想要的)
BR> i2.equals(i3); true
i2.equals(d2) ; false
逻辑操作符
逻辑运算符:&&,||,!只能用boolean值身上。位运算符:&,|,^,~:在两个操作数的相应位上进行逻辑代数运算。boolean数据不能~b而用!b。&和|和^即是逻辑的(逻辑与,逻辑或和逻辑非)也是位操作的运算符(按位与,按位或和按位异或)。
奇怪的&&与||(短路的&&和||)
当第一个操作数为flase时,如果用&&运算符时,则不检查第二个操作数就直接返回flase。
当第一个操作数为true时,如果用||运算符时,则不检查第二个操作数就直接返回true。
移位操作符
无符号右移位操作符>>>,它采用零扩展,高位插入0. 左移位运算符<< 能将运算符左边的运算对象向左移动运算符右侧指定的位数在低位补0。有符号右移位运算符>> 则将运算符左边的运算对象向右移动运算符右侧指定的位数,有符号右移位运算符使用了符号扩展。若值为正则在高位插入0,若值为负则在高位插入1。
注:int或<int的数据类型进行位移操作数先要进行mode 32运算所以对大于32的位移运算,先要进行mode 32运算,所以3>>>32的结果为3。Long数据类型在先要进行mode 64运算。
奇怪的>>>:小的负数进行>>>运算将得到一个大的正数
-1>>>1 : 2147483647
A unsigned right shift >>> by a positive amount of a small negative number will result in a large positive number returned.
操作数的优先级
优先级(胃溃疡患者是c程序员的写照 Ulcer Addicats Really Like C A lot)
U: ->Unary 一元运算符 ++, -- ,-,+,!,~
A: -> Arithmetic(shift) *,/,%,+,-,>>,>>>,<<
R: -> Relation >,<,>=,<=,instanceof,==,!=
L: -> Logic(bitwise) &,^,|,&&,||
C: -> 三元运算符
A:-> 赋值 = *=
Objective 2, the equals method
Determine the result of applying the boolean equals(Object) method to objects of any combination of the classes java.lang.String java.lang.Boolean and java.lang.Object.
目标2 equals方法
学会使用对象的equals方法。
equals()和==
equals()用于检测对象的值,即检测对象所引用的内部数据的值。只能用于引用类型。
==用于检测对象引用自身,是否指向同一块内存地址。可用于基本类型,也可用于引用类型。当用于引用类型时,两边的类型必须一至。
默认情况下,equals()和==的返回结果是一样的,是拿references来比较的,但是java标准类库中的大多数类覆盖了equals()。例如:
String类,String对象在代表相同字符串时相等。equals()返回真。
Boolean对象在值相同时相等。equals()返回真。
类型不兼容的两个对象可以用equals(),但是只要比较的对象类型不同(哪怕值相同),永远返回false
一般来说,equals方法认为是一种对象之间的深度比较而==认为是一种浅比较。equals比较引用所指向的内容而不是引用本身。
String的equals方法:
在java中有两种生成String的方法: String s=new String("Hello"); 和 String s="Hello";
这种方法之间的微小区别在于不使用new关键字生成的String将指向String Pool中的相同String.
Boolean的equals方法:
当且仅当lean值相同时,equals方法返回true。
Object的equals方法:
object的equals方法测试的对象是对象的toString()方法所返回的值。而对象的toString()方法仅返回对象的内存地址。所以,它与==操作的功能相同。
注意: StringBuffer类没有覆写equals方法。所以
StringBuffer buf1=new StringBuffer(“123”); StringBuffer buf2=new StringBuffer(“123”);
buf1==buf2: false buf1.equasl(buf2): false
示例: equals方法
public class MyParm{
public static void main(String argv[]){
String s1= "One";
String s2 = "One";
String s3=new String("One");
String s4=new String("One");
MyObj obj1=new MyObj("One");
MyObj obj2=new MyObj("One");
System.out.println("s1: "+ s2+" s2: "+s2+" s3: "+s3+" s4: "+s4);
if(s1.equals(s2)){ //s1,s2指向String Pool的相同String对象返回true
System.out.println("String equals 1");
}
if(s1==s2){ //同上,返回true
System.out.println("String equals 2");
}
if(s1.equals(s3)){ //String覆写了equals方法,返回true
System.out.println("String equals 3");
}
if(s1==s3){ //返回false
System.out.println("String equals 4");
}
if(s3.equals(s4)){ // String覆写equals方法,返回true
System.out.println("String equals 5");
}
if(s3==s4){ //s3,s4是不同的String对象,返回false
System.out.println("String equals 6");
}
boolean b1 = true;
boolean b2 = true;
Boolean b3 = new Boolean(true);
Boolean b4 = new Boolean(true);
if(b3.equals(b4)){ //Boolean覆写了equals方法,返回true
System.out.println("boolean equals 7");
}
if(b3==b4){ //不同的对象,返回false
System.out.println("boolean equals 8");
}
//if(b3==b1){ //不同的数据类型不能==
//System.out.println("String equals 6");
//}
//if(b1.equals(b2)){//基本数据类型没有方法
// System.out.println("true");
//}
if(obj1.equals(obj2)){ //MyObj覆写了equals方法,返回true
System.out.println("Obj equals 9");
}
}
}
class MyObj{
String s;
MyObj(String s){
this.s=s;
}
public String toString(){
return s;
}
public boolean equals(MyObj o){
if(s.equals(o.s)) return true;
else return false;
}
public int hashCode(){
return s.hashCode();
}
}
Objective 3, The & | && and || operators
In an expression involving the operators & | && || and variables of known values state which operands are evaluated and the value of the expression.
目标3 &,|,&&,||操作符
&,|: 位操作符
&&,||: 逻辑操作符
&&,||的短路行为:
当第一个操作数为flase时,如果用&&运算符时,则不检查第二个操作数就直接返回flase。
当第一个操作数为true时,如果用||运算符时,则不检查第二个操作数就直接返回true。
&,|:位操作符用于整数型的基本数据类型。对于boolean数据来说,逻辑与位操作符大约相同,位操作符没有短路行为。
示例:
public class MyClass1{
public static void main(String argv[]){
int Output=10;
boolean b1 = false;
if((b1==true) && ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
if((b1==true) & ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
if((b1==true) || ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
if((b1==false) | ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
}
}
Objective 4, Passing objects and primitives to methods
Determine the effect upon objects and primitive values of passing variables into methods and performing assignments or other modifying operations in that method.
目标4 方法中的参数
方法对传入的参数(对象和基本类型)的影响
当你传入一个值到方法中后将发生什么了?
所有的参数(基本类型的值和对象引用值)都是传值。
基本类型的参数是原数据的一个拷贝,因此,在方法中对它的所有修改在返回后都不可见了。
对象引用型的参数尽管也是原数据引用的一个拷贝,但是由于java中对象是通过对象引用来操作的,因此,在方法中对对象属性的修改,在返回??在返回后则不可见。
示例:
class ValHold{
public int i = 10;
}
public class ObParm{
public static void main(String argv[]){
ObParm o = new ObParm();
o.amethod();
o.othermethod();
}
public void amethod(){
ValHold v = new ValHold(); // v是一个对象引用
System.out.println("Before another ="+v);
v.i=10;
System.out.println("Before another = "+ v.i);
another(v); // v作为方法的参数,方法就具有了对象引用的值,v的对象引用在方法返回后不变
System.out.println("After another = "+ v.i);
System.out.println("After another = "+v);
}//End of amethod
public void another(ValHold v){
System.out.println("In another= "+v);
v.i = 20; //修改对象引用中属性的值
ValHold v1=new ValHold();
v=v1; //修改了对象引用值,由于v是对象引用的一个拷贝,它的改变不影响返回后的对象引用
System.out.println("modified "+v);
System.out.println("In another = "+ v.i);
}//End of another
public void othermethod(){
int i=10;
System.out.println("Before another i= " +i);
another(i);
System.out.println("After another i= " + i);
}
public void another(int i){
i+=10;
System.out.println("In another i= "+i);
}
}
Section 6 Overloading, overriding, runtime type and OO
Objective 1, Encapsulation and OO design
State the benefits of encapsulation in object oriented design and write code that implements tightly encapsulated classes and the relationships "is a" and "has a".
目标1 封装与OO设计
说明封装与OO设计的好处并实现封装类和“is a ”和“has a ”关系
“is a” 和”has a ”关系
“is a ”关系就是继承(inheriatnce)语法。继承的语法:
class BaseClass{}
class DerivedClass extends BaseClass{}
继承类自动获得基类的所有数据成员和成员函数。
“has a”关系就是组合(composition)语法。就是将对象引用置于新的类中。组合的语法:
class CompositedClass{
CompositingClass1 aClass1;
CompositingClass2 aClass2;
….
}
在组合的类之中,属于基本类型的数据,会自动初始化为0,则对象引用被初始化为null,而且如果你试着通过这些引用调用任何函数,会引起异常。
封装
封装是将类的接口与实现公开。接口提供了类的访问方法,其它类只有通过这些访问方法才能访问类的数据。封装的一种方法是将类的成员数据设有私有(private),并通过方法来获得或修改这些数据。
这些方法的标准表示为:
setFileName (setter方法) getFieldName(getter方法)
例如:
private Color fColor;
public void setFColor(Color c){fColor=c;}
public Color getFColor(){return fColor;}
Encapsulation involves hiding data of a class and allowing access only through a public interface.
封装的好处在于对类内部的实现的修改将不影响使用这个类的方法。类的使用者不需要清楚类的内部工作方式只要使用定义好的接口来处理数据。
执行期类型
继承技术中最重要的一个方面是向上转型(Upcasting),就是继承类移至基类。向上转型是安全的,因为这是从专用类型移至通用类型。因此,你不必明确表示转型,编译器仍然允许向上转型。在你面对使用组合或继承时,“我需要向上转型吗”是一个极佳的判断工具。在Java中通过后期绑定(late binding)来实现方法动态调用。后期绑定也可理解为动态绑定或“发送消息给某个对象,让该对象自行找到应该做的事”
向下强制转型:
在Java 中所有强制转型都会自动得到检查和核实。所以即使我们只是进行一次普通的括弧强制转型,进入运行时间以后,仍然会毫不留情地对这个强制转型进行检查保证它的确是我们希望的那种类型。如果不是,就会得到一个ClassCastException(类强制转型违例)。在程序运行时对类型进行检查的行为叫作运行时间类型标识Run-Time Type Identification(RTTI)。
总结: 向上转型是安全的,向下转型必须保证转型类型的一致性。
示例:
class Base {
int i=99;
public void amethod(){
System.out.println("Base.amethod()");
}
Base(){
amethod();
}
int getI(){return i;}
}
class Rt extends Base{
}
public class RType extends Base{
int i=-1;
public static void main(String argv[]){
Base b = new RType();
Base b1=new Base();
RType t=new RType();
//b1=t;
t=(RType)b1; //向下转型错误。b1实际上指向的是Base
t=(RType)b; //向下转型正确。
b.onlyyou(); //错误,Base类不提供onlyyou方法,尽管b实际上是RType
System.out.println(b.i);
System.out.println(b.getI());
b.amethod();
}
public void amethod(){
System.out.println("RType.amethod()");
}
int getI(){return i;}
public void onlyyou(){
}
}
Objective 2, Overriding and overloading
Write code to invoke overridden or overloaded methods and parental or overloaded constructors; and describe the effect of invoking these methods.
重载
如果同一个类中的多个方法有不同的参数列表,那么它们可以具有相同的名称。编译器在区分方法时不考虑返回类型,所以不能声明两个具有相同参数列表但返回类型不同的方法。
覆写与隐藏
如果子类中的一个实例方法与超类的一个实例方法具有相同的标记和返回类型,这被称为子类方法覆写了(override)超类方法。(记住,方法的标记包括它的名称,参数数量和参数类型)。子类覆写方法的能力允许从超类继承行为不同的 throws子句,但没有指定被覆写方法的throws子句没有指定的任何类型。
另外,覆写的方法的访问修饰符不能被被覆写的方法的访问修饰符严格,例如,超类中的保??的。子类不能覆写超类中的final方法。
子类必须覆写超类中声明为abstract的方法,否则子类本身必须是抽象的。
在编写与超类同名的方法时,分清是重载还是覆写,具有相同方法标记的是覆写,具有不同参数数量和类型的的是重载。
如果子类定义的类方法与超类的类方法具有相同的标记,那么子类方法隐藏超类的方法。
实例方法不能覆盖静态方法,而静态方法不能隐藏实例方法。
隐藏成员变量
在类中,如果一个成员变量与超类的成员变量同名(即使类型不同),那么它隐藏超类的成员变量。
在子类中,不能通过简单的名称引用超类的成员变量,而是必须通过super访问它。
示例:类的覆写与重载
class ClassA {
public int value=1;
public void methodOne(int i) {
System.out.println("ClassA methodOne");
}
public void methodTwo(int i) {
System.out.println("ClassA methodTwo");
}
public static void methodThree(int i) {
System.out.println("ClassA methodThree");
}
public static void methodFour(int i) {
System.out.println("ClassA methodFour");
}
int getValue(){return value;}
}
public class ClassB extends ClassA {
public double value=1.0;
public void methodOne(int i) {
System.out.println("ClassB methodOne");
}
public void methodTwo(int i) {
System.out.println("ClassB methodTwo");
}
public static void methodThree(int i) {
System.out.println("ClassA methodThree");
}
public static void methodFour(int i) {
System.out.println("ClassA methodFour");
}
public void methodFive(double value){
this.value=value;
System.out.println("value="+value);
System.out.println("super.value="+super.value);
}
public static void main(String[] args){
ClassA a=new ClassB();
a.methodOne(1);
a.methodThree(1);
ClassB b=(ClassB)a;
b.methodFive(2.0);
}
//double getValue(){return value;}
}
初始化与类的装载
Java的类加载方式:在java中每个类都在专属的.class文件中,这些文件只有在必要时才被装载。也就是说:“类程序代码在初次被使用时才被装载”。所谓的初次被使用,不仅是其第一个对象被建构之时,也可能是在某个static数据成员或static函数被取用时。“初次使用类”的时间点也是静态初始化进行的时机。
示例:关于类加载与初始化过程
class A{
int i;
A(int i){
this.i=i;
System.out.println("A constructor"+i);
}
A(){System.out.println("A constructor");}
static{
int i=7;
System.out.println("i="+i);
}
}
class Insect {
protected static A a=new A();
private int i = 9;
protected int j;
Insect() {
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
private static int x1 =
print("static Insect.x1 initialized");
static int print(String s) {
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect {
private int k = print("Beetle.k initialized");
private A a=new A();
public Beetle() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
private static int x2 =
print("static Beetle.x2 initialized");
public static void main(String[] args) {
System.out.println("Beetle constructor");
Beetle b = new Beetle();
}
}
分析上面程序的初始化过程:
程序的入口在Beetle.main()方法。程序执行时,类装载器被启动,找到Beetle.class并装载,由于Beetle类是Insect类的子类所以类装载器也将Insect.class装载。如果基类还要基类,这个过程将继续。
类加载完成后,将进行静态初始化过程,首先从根基类(Insect)开始,然后是其子类(Bettle),依次类推。在本例中,执行Insect 类中protected static A a=new A();类加载器装载A.class并进行静态初始化过程:A类中的static块,然后构造函数。然后,private static int x1 = print("static Insect.x1 initialized");最后是Beetle类中的private static int x2 = print("static Beetle.x2 initialized");
静态初始化完成后,将进行类实例的生成。首先,对象内的所有基本类型都会被评为设予缺省值,对象引用则被设予null.然后,基类的构造函数被唤起,缺省条件下基类的缺省构造函数被自动唤起,但你可用super(第一个运作)来调用基类的其它构造函数。执行Insect类的缺省函数。
基类构造完成后,是实例变量按次序被初始化,最后,才执行构造本体的剩余部分。
final类, 方法,变量
final变量是固定不变的数据。它可以:
可以是永不改变的编译期常量(compile-time constant)
可以是执行期(runtime)被初始化,而你不想再改变它。
final的对象引用的意义是它让引用保持不变而不是对象本身。某个引用一旦被初始化后,便再也不能指向另一个对象,但此对象本身的内容是可以改变的。
Java允许产生所谓的”blank finals”,也就是允许我们将数据成员声明为final,却不给予初值。注意:在任何情况下,blank finals必须在使用之间进行初始化, 而且编译器保证此事。所以,final的赋值运行如果不是发生在其定义处,就得在构造函数中以表达式设定其值。
final参数
?
final方法
final方法的原因: 第一:锁住这个函数,使子类不能改意其意义,即无法覆写;第二:效率。
类中的?在子类中隐藏,final函数却不能。
final类
final类就是说此类不能被继承。final类中的所有方法是final的但数据成员可是fianl也可不是fianl.
示? class Value {
int i; // Package access
public Value(int i) { this.i = i; }
private final void aMethod(){ //final??can be omitted
System.out.println("In Value.aMethod");
}
final void anotherMehtod(){
System.out.println("In Value.anotherMethod");
}
}
class SuperValue extends Value{
SuperValue(){super(1);}
void aMethod(){System.out.println("In SuperValue");}
//void anotherMethod(){} //final??method can not be changed
}
public class FinalData {
private static Random rand = new Random();
private String id;
public FinalData(String id,int j) { this.id = id; VAL_ONE=1; }
// Can be compile-time constants:
private final int VAL_ONE ; //bland final
private static final int VAL_TWO ;
static{
VAL_TWO=4;
}
// Typical public constant:
public static final int VAL_THREE = 39;
// Cannot be compile-time constants:
private final int i4 = rand.nextInt(20);
static final int i5 = rand.nextInt(20);
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
private static final Value v3 = new Value(33);
// Arrays:
private final int[] a = { 1, 2, 3, 4, 5, 6 };
public String toString() {
return id + ": " + "i4 = " + i4 + ", i5 = " + i5;
}
public static void main(String[] args) {
FinalData fd1 = new FinalData("fd1",9);
//! fd1.VAL_ONE++; // Error: can't change value
fd1.v2.i++; // Object isn't constant!
fd1.v1 = new Value(9); // OK -- not final
for(int i = 0; i < fd1.a.length; i++)
fd1.a++; // Object isn't constant!
//! fd1.v2 = new Value(0); // Error: Can't
//! fd1.v3 = new Value(1); // change reference
//! fd1.a = new int[3];
System.out.println(fd1);
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData("fd2",8);
System.out.println(fd1);
System.out.println(fd2);
Value v1=new SuperValue();
SuperValue v2=new SuperValue();
v2.aMethod();
//!v1.aMethod();
}
} ///:~
Objective 3, Creating class instances
Write code to construct instances of any concrete class including normal top level classes inner classes static inner classes and anonymous inner classes.
抽象类与抽象函数
抽象类是不能实例化的类,它定义了一组继承类的通用接口,继承类中所有的与抽象类标记相同的方法,会通过动态绑定的机制来调用。
抽象函数是一种不完全的函数,只有声明而无本体。具有抽象函数的类必须声明为abstract。
如果你要继承一个抽象类,你得实现抽象类中所有的抽象方法。否则,你的继承类也得声明为abstract.
不含任向abstract函数的类也可声明为抽象。
嵌套类(nested class)
嵌套类是另一个类的成员,反映了两个类之间的关系。当嵌套类只在包含它的类中有意义,或者它依赖于包含它的类来实现功能时,应该在另一个类中定义这个类。
嵌套类的特权: 它可以限制的访问包含它的类的成员,即使这些成员是私有的,嵌套类也可以访问它。
嵌套类可分为:静态嵌套类也称为(nested class)。非静态嵌套类也称为(inner class)
inner class
inner class不能具有任何static类型的data,fields,inner class.
匿名的inner类
只有用于实现事件接口。匿名inner类不能拥有构造函数。同时,匿名类一般与位于函数或Scopes内的类,所以它只接收外部的final数据。对匿名类的数据成员的初始化:一是在定义处,二是使用实体初始化(instance initialization).
示例: 匿名inner类
Section 7 Threads
Objective 1, Instantiating and starting threads
Write code to define, instantiate and start new threads using both java.lang.Thread and java.lang.Runnable
目标1 使用Thread类或Runnable接口定义,实例化和启动线程
什么是线程
线程是轻量级的进程,它能在主程序中并发执行。不同于进程,线程与进程中其它的线程共享内存与数据。
在JSCP考试中你要清楚一个概念:当程序启动了一个线程后,程序就有了多个执行路径。例如:线程A在线程B之前启动,这并不意味A必然先B执行完毕。程序的输出可能与底层的操作系统或系统中的已运行程序有关。
定义线程的两种方式
方式一:类实现Runnable接口
Runnable接口的定义:
public Interface Runnable{
public void run();
}
定义线程:
class MyClass implements Runnable{
public void run(){//Blank Body}
}
实例线程:
MyClass mc = new MyClass();
MyClass mc2 = new MyClass();
Thread t = new Thread(mc);
Thread t2 = new Thread(mc2);
t.start();
t2.start();
注意:实例实现Runnable接口线程,需要先实例Thread并将Runnable类作为构造器参数传递给Thread构造器。Thread的构造器方法之一:
Thread(Runnable target) 或者Thread(Runnable target, String name)
方式二: 类继承在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。注意: 这种方式直接明了但这也意味由于java只支持单一继承,所以你的子类不能再继承其它的类了。
定义线程
public class MyThread extends Thread {
public void run(){}
}
实例线程
MyThread t=new MyThread();
t.start();
实例化和启动线程
尽管线程的运行时做的事由run方法提供,但启动线程不是直接调用run方法,而是调用start方法。start方法分配运行线程所需的资源,调度线程运行,并调用线程的run方法。注意:你可以直接调用run方法,这时,run方法仅视为普通的方法而不是线程的一部分。
Although it is the run method code that executes, a thread is actually started via the start method.
示例:
public class Runt extends Thread{
public Runt(String name){
super(name);
}
public static void main(String argv[]){
for(int i=0;i<3;i++){
Runt r = new Runt(""+i);
r.run();
}
System.out.println("Begin To run concurrently");
for(int i=0;i<3;i++){
Runt r = new Runt(""+i);
r.start();
}
}
public void run(){
for(int i=0;i<10;i++)
System.out.println("# Thread-"+getName()+"-"+i);
}
}
Objective 2, When threads are prevented from executing
Recognise conditions that might prevent a thread from executing.
目标2 线程停止的原因
明确线程阻塞的条件
线程的四种状态
1. 新状态(New Thread):线程已被创建但尚未执行(start() 尚未被调用)。
2. 可执行状态(Runnable):线程可以执行,虽然不一定正在执行。CPU 时间随时可能被分配给该线程,从而使得它执行。
3. 死亡状态(Dead):正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果,但是不被推荐,前者会产生异常,后者是强制终止,不会释放锁。
4. 阻塞状态(Not Runnable):线程不会被分配 CPU 时间,无法执行。
线程阻塞的原因(Runnable->Not Runnable)
线程进入睡眠状态,那么必须经过指定的时间后线程返回可运行状态
线程由于调用wait而处于暂停状态,另一个对象调用了notfiy或notifyAll通知等待线程
线程由于IO操作而阻塞,IO完成后线程返回可运行状态
线程由于调用suspend()而阻塞,接到resume()后返回可运行状态(Deprecated)
sleep和wait/notify是引起阻塞的主要原因。
public static void sleep(long millis) throws InterruptedException
sleep方法是一个静态方法,它以以毫秒为单位的一段时间作为参数,使线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。注意:sleep方法抛出异常,在调用它时要捕捉这个异常。
线程的yield()方法(Running->Runnable)
public static void yield();
线程的yield方法使当前线程放弃对CPU资源的占用,线程进入Runable状态。由线程调度算法来选择其它Runnable线程runing.
操作系统的调度系统
时间片(Time Slicing)/抢占式(preemptive)
时间片系统将CPU分割为很短的时间段,并给每个具有相等而且最高优先级的线程分配时间段以供运行。时间片系统遍历具有相等且最高优先级的线程,允许它们各自运行一小段时间,直到其中一个或多个完成执行或一个具有更高优先级的线程抢占它们。Windows系统采用了抢占式调度。
非时间片(Non Time Slicing)/合作式(Cooperative)
由优先系统决定线程的运行,最高优先级的线程获得CPU时间。在这种机制下,程序要通过某种方式自动的放弃CPU时间。
示例:
public class SelfishRunner extends Thread {
private int tick = 1;
private int num;
public SelfishRunner(int num) {
this.num = num;
}
public void run() {
while (tick < 400000) {
tick++;
if ((tick % 50000) == 0){
System.out.println("Thread #" + num + ", tick = " + tick);
//yield(); //!自私的线程与公平的线程
}
}
}
}
public class RaceDemo {
private final static int NUMRUNNERS = 2;
public static void main(String[] args) {
SelfishRunner[] runners = new SelfishRunner[NUMRUNNERS];
for (int i = 0; i < NUMRUNNERS; i++) {
runners = new SelfishRunner(i);
runners.setPriority(2);
}
for (int i = 0; i < NUMRUNNERS; i++)
runners.start();
}
}
Objective 3, The wait/notify protocol
Write code using synchronized wait notify and notifyAll to protect against concurrent access problems and to communicate between threads. Define the interaction between threads and between threads and object locks when executing synchronized wait notify or notifyAll.
由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。这出就是线程同步的问题。
synchronized关键字
synchronzied关键字用于标识临界区(critical section)。临界区是单独的并发线程可访问期间的相同对象的代码段。它可以是一段代码或方法。名词Monitor,mutex(mutually exclusive lock)是指实现同步所需要的lock. Java平台将一个锁与每个具有同步代码的对象关联起来。当某个线程进入同步方法时,线程就锁定了此方法的对象。在对象被解锁前,其它线程不能调用??不是基于方法的。同步的方法的实现:
synchronized void amethod() { /* method body */}
或
synchronized (ObjectReference) { /* Block body */ }
When a synchronized block is executed, its object is locked and it cannot be called by any other code until the lock is freed.
wait/notify/notifyAll
public final void wait() throws InterruptedException
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout,int nanos) throws InterruptedException
public final void notify()
public final void notifyAll()
为了获得和释放lock,每个对象都能pause或wait,直到其它对象将锁转效到它。Wait/notify是线程间通信的一种方式。由于它们是Object类所具有的方法,所以在JAVA中所有的类都具有了线程通信的能力。调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。一对方法却必须在 synchronized 方法或块中调用,理由也很简单,只有在synchronized 方法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,这一对方法调用必须放置在这样的 synchronized 方法或块中,该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException 异常。如果没有notify方法,wait方法将毫无意义。因为它通知那些由于wait而阻塞的线程使它们能继续运行。
wait and notify should be placed within synchronized code to ensure that the current code owns the monitor
方法的使用
while(true){
try{
wait();
}catch (InterruptedException e) {}
}
//some producing action goes here
notifyAll();
注:notifyAll方法唤醒所有等待相关对象的线程。被唤醒的线程序争夺锁。一个线程得到锁,其它线程继续等待。notify方法,它任意唤醒等待此对象的线程之一。
示例:生产/消费者问题
public class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait();
} catch (InterruptedException e) { }
}
available = false;
notifyAll();
return contents;
}
public synchronized void put(int value) {
while (available == true) {
try {
wait();
} catch (InterruptedException e) { }
}
contents = value;
available = true;
notifyAll();
}
}
生产者
public class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" + this.number
+ " put: " + i);
try {
sleep((int)(Math.random() * 100));
基本数据类型的赋值操作
boolean数据只能赋值于另一个boolean数据。不同于c和c++,java中的boolean值只能是true和false。
其它的数据类型可以自由的进行widening conversion(宽化转换)。而进行narrowing conversion(窄化转换)由于有精度的损失,必须进行强制转换。
Primitives may be assigned to "wider" data types, a boolean can only be assigned to another boolean
引用数据类型的赋值操作
引用数据类型的赋值,例如a=b,使得a和b引用指向相同的对象。引用数据类型的赋值可以向上转型。即一超类的引用可以被赋值一子类对象。但向下转型必须强制转换。
Object references can be assigned up the hierarchy from child to base.
示例: 赋值操作符
class SuperClass {
int i;
}
class Child1 extends SuperClass{
int j;
}
class Child2 extends SuperClass{
int k;
}
public class Assignment {
public static void main(String[] args) {
//primitive datatype
boolean b=false;
int i=0;
char c='e';
byte bt=0;
short s=0;
long l=12;
float f =32.0f;
double d=21.0;
// widening conversion
//i=b;
i=c;
i=bt;
i=s;
f=l;
// narrowing conversion
bt=(byte)i;
s=(short)c;
//reference datatype
SuperClass n1 = new Child1();
SuperClass n2 = new SuperClass();
SuperClass n3 = new Child2();
Child1 c1=new Child1();
Child2 c2=new Child2();
n1.i = 9;
n2.i = 47;
System.out.println("1: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1 = n2;
System.out.println("2: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1.i = 27;
System.out.println("3: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1=n3;
n1.i=4;
System.out.println("3: n1.i: " + n1.i +
", n3.i: " + n3.i);
//! c1=(Child1)c2;
}
}
++,--: 前序递增和前序递减(++a,--a)先进行运算然后才增赋值。后序递增和后序递减(a++,a--)先赋值然后才进行运算。
奇怪的++与--:
int a=1,b=5;
b+=b++-a--; (b=9)
b=b++;(b=9)
b=++b; (b=10)
关系操作符
关系操作符(<,>,<=,>=,==,!=)所产生的结果是boolean,==,!=可用于所有的内置的类型,其它运算符不能用于boolean.
奇怪的==(对于引用类型==比较两个对象的内存地址,这可不是我们想要的)
BR> i2.equals(i3); true
i2.equals(d2) ; false
逻辑操作符
逻辑运算符:&&,||,!只能用boolean值身上。位运算符:&,|,^,~:在两个操作数的相应位上进行逻辑代数运算。boolean数据不能~b而用!b。&和|和^即是逻辑的(逻辑与,逻辑或和逻辑非)也是位操作的运算符(按位与,按位或和按位异或)。
奇怪的&&与||(短路的&&和||)
当第一个操作数为flase时,如果用&&运算符时,则不检查第二个操作数就直接返回flase。
当第一个操作数为true时,如果用||运算符时,则不检查第二个操作数就直接返回true。
移位操作符
无符号右移位操作符>>>,它采用零扩展,高位插入0. 左移位运算符<< 能将运算符左边的运算对象向左移动运算符右侧指定的位数在低位补0。有符号右移位运算符>> 则将运算符左边的运算对象向右移动运算符右侧指定的位数,有符号右移位运算符使用了符号扩展。若值为正则在高位插入0,若值为负则在高位插入1。
注:int或<int的数据类型进行位移操作数先要进行mode 32运算所以对大于32的位移运算,先要进行mode 32运算,所以3>>>32的结果为3。Long数据类型在先要进行mode 64运算。
奇怪的>>>:小的负数进行>>>运算将得到一个大的正数
-1>>>1 : 2147483647
A unsigned right shift >>> by a positive amount of a small negative number will result in a large positive number returned.
操作数的优先级
优先级(胃溃疡患者是c程序员的写照 Ulcer Addicats Really Like C A lot)
U: ->Unary 一元运算符 ++, -- ,-,+,!,~
A: -> Arithmetic(shift) *,/,%,+,-,>>,>>>,<<
R: -> Relation >,<,>=,<=,instanceof,==,!=
L: -> Logic(bitwise) &,^,|,&&,||
C: -> 三元运算符
A:-> 赋值 = *=
Objective 2, the equals method
Determine the result of applying the boolean equals(Object) method to objects of any combination of the classes java.lang.String java.lang.Boolean and java.lang.Object.
目标2 equals方法
学会使用对象的equals方法。
equals()和==
equals()用于检测对象的值,即检测对象所引用的内部数据的值。只能用于引用类型。
==用于检测对象引用自身,是否指向同一块内存地址。可用于基本类型,也可用于引用类型。当用于引用类型时,两边的类型必须一至。
默认情况下,equals()和==的返回结果是一样的,是拿references来比较的,但是java标准类库中的大多数类覆盖了equals()。例如:
String类,String对象在代表相同字符串时相等。equals()返回真。
Boolean对象在值相同时相等。equals()返回真。
类型不兼容的两个对象可以用equals(),但是只要比较的对象类型不同(哪怕值相同),永远返回false
一般来说,equals方法认为是一种对象之间的深度比较而==认为是一种浅比较。equals比较引用所指向的内容而不是引用本身。
String的equals方法:
在java中有两种生成String的方法: String s=new String("Hello"); 和 String s="Hello";
这种方法之间的微小区别在于不使用new关键字生成的String将指向String Pool中的相同String.
Boolean的equals方法:
当且仅当lean值相同时,equals方法返回true。
Object的equals方法:
object的equals方法测试的对象是对象的toString()方法所返回的值。而对象的toString()方法仅返回对象的内存地址。所以,它与==操作的功能相同。
注意: StringBuffer类没有覆写equals方法。所以
StringBuffer buf1=new StringBuffer(“123”); StringBuffer buf2=new StringBuffer(“123”);
buf1==buf2: false buf1.equasl(buf2): false
示例: equals方法
public class MyParm{
public static void main(String argv[]){
String s1= "One";
String s2 = "One";
String s3=new String("One");
String s4=new String("One");
MyObj obj1=new MyObj("One");
MyObj obj2=new MyObj("One");
System.out.println("s1: "+ s2+" s2: "+s2+" s3: "+s3+" s4: "+s4);
if(s1.equals(s2)){ //s1,s2指向String Pool的相同String对象返回true
System.out.println("String equals 1");
}
if(s1==s2){ //同上,返回true
System.out.println("String equals 2");
}
if(s1.equals(s3)){ //String覆写了equals方法,返回true
System.out.println("String equals 3");
}
if(s1==s3){ //返回false
System.out.println("String equals 4");
}
if(s3.equals(s4)){ // String覆写equals方法,返回true
System.out.println("String equals 5");
}
if(s3==s4){ //s3,s4是不同的String对象,返回false
System.out.println("String equals 6");
}
boolean b1 = true;
boolean b2 = true;
Boolean b3 = new Boolean(true);
Boolean b4 = new Boolean(true);
if(b3.equals(b4)){ //Boolean覆写了equals方法,返回true
System.out.println("boolean equals 7");
}
if(b3==b4){ //不同的对象,返回false
System.out.println("boolean equals 8");
}
//if(b3==b1){ //不同的数据类型不能==
//System.out.println("String equals 6");
//}
//if(b1.equals(b2)){//基本数据类型没有方法
// System.out.println("true");
//}
if(obj1.equals(obj2)){ //MyObj覆写了equals方法,返回true
System.out.println("Obj equals 9");
}
}
}
class MyObj{
String s;
MyObj(String s){
this.s=s;
}
public String toString(){
return s;
}
public boolean equals(MyObj o){
if(s.equals(o.s)) return true;
else return false;
}
public int hashCode(){
return s.hashCode();
}
}
Objective 3, The & | && and || operators
In an expression involving the operators & | && || and variables of known values state which operands are evaluated and the value of the expression.
目标3 &,|,&&,||操作符
&,|: 位操作符
&&,||: 逻辑操作符
&&,||的短路行为:
当第一个操作数为flase时,如果用&&运算符时,则不检查第二个操作数就直接返回flase。
当第一个操作数为true时,如果用||运算符时,则不检查第二个操作数就直接返回true。
&,|:位操作符用于整数型的基本数据类型。对于boolean数据来说,逻辑与位操作符大约相同,位操作符没有短路行为。
示例:
public class MyClass1{
public static void main(String argv[]){
int Output=10;
boolean b1 = false;
if((b1==true) && ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
if((b1==true) & ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
if((b1==true) || ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
if((b1==false) | ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
}
}
Objective 4, Passing objects and primitives to methods
Determine the effect upon objects and primitive values of passing variables into methods and performing assignments or other modifying operations in that method.
目标4 方法中的参数
方法对传入的参数(对象和基本类型)的影响
当你传入一个值到方法中后将发生什么了?
所有的参数(基本类型的值和对象引用值)都是传值。
基本类型的参数是原数据的一个拷贝,因此,在方法中对它的所有修改在返回后都不可见了。
对象引用型的参数尽管也是原数据引用的一个拷贝,但是由于java中对象是通过对象引用来操作的,因此,在方法中对对象属性的修改,在返回??在返回后则不可见。
示例:
class ValHold{
public int i = 10;
}
public class ObParm{
public static void main(String argv[]){
ObParm o = new ObParm();
o.amethod();
o.othermethod();
}
public void amethod(){
ValHold v = new ValHold(); // v是一个对象引用
System.out.println("Before another ="+v);
v.i=10;
System.out.println("Before another = "+ v.i);
another(v); // v作为方法的参数,方法就具有了对象引用的值,v的对象引用在方法返回后不变
System.out.println("After another = "+ v.i);
System.out.println("After another = "+v);
}//End of amethod
public void another(ValHold v){
System.out.println("In another= "+v);
v.i = 20; //修改对象引用中属性的值
ValHold v1=new ValHold();
v=v1; //修改了对象引用值,由于v是对象引用的一个拷贝,它的改变不影响返回后的对象引用
System.out.println("modified "+v);
System.out.println("In another = "+ v.i);
}//End of another
public void othermethod(){
int i=10;
System.out.println("Before another i= " +i);
another(i);
System.out.println("After another i= " + i);
}
public void another(int i){
i+=10;
System.out.println("In another i= "+i);
}
}
Section 6 Overloading, overriding, runtime type and OO
Objective 1, Encapsulation and OO design
State the benefits of encapsulation in object oriented design and write code that implements tightly encapsulated classes and the relationships "is a" and "has a".
目标1 封装与OO设计
说明封装与OO设计的好处并实现封装类和“is a ”和“has a ”关系
“is a” 和”has a ”关系
“is a ”关系就是继承(inheriatnce)语法。继承的语法:
class BaseClass{}
class DerivedClass extends BaseClass{}
继承类自动获得基类的所有数据成员和成员函数。
“has a”关系就是组合(composition)语法。就是将对象引用置于新的类中。组合的语法:
class CompositedClass{
CompositingClass1 aClass1;
CompositingClass2 aClass2;
….
}
在组合的类之中,属于基本类型的数据,会自动初始化为0,则对象引用被初始化为null,而且如果你试着通过这些引用调用任何函数,会引起异常。
封装
封装是将类的接口与实现公开。接口提供了类的访问方法,其它类只有通过这些访问方法才能访问类的数据。封装的一种方法是将类的成员数据设有私有(private),并通过方法来获得或修改这些数据。
这些方法的标准表示为:
setFileName (setter方法) getFieldName(getter方法)
例如:
private Color fColor;
public void setFColor(Color c){fColor=c;}
public Color getFColor(){return fColor;}
Encapsulation involves hiding data of a class and allowing access only through a public interface.
封装的好处在于对类内部的实现的修改将不影响使用这个类的方法。类的使用者不需要清楚类的内部工作方式只要使用定义好的接口来处理数据。
执行期类型
继承技术中最重要的一个方面是向上转型(Upcasting),就是继承类移至基类。向上转型是安全的,因为这是从专用类型移至通用类型。因此,你不必明确表示转型,编译器仍然允许向上转型。在你面对使用组合或继承时,“我需要向上转型吗”是一个极佳的判断工具。在Java中通过后期绑定(late binding)来实现方法动态调用。后期绑定也可理解为动态绑定或“发送消息给某个对象,让该对象自行找到应该做的事”
向下强制转型:
在Java 中所有强制转型都会自动得到检查和核实。所以即使我们只是进行一次普通的括弧强制转型,进入运行时间以后,仍然会毫不留情地对这个强制转型进行检查保证它的确是我们希望的那种类型。如果不是,就会得到一个ClassCastException(类强制转型违例)。在程序运行时对类型进行检查的行为叫作运行时间类型标识Run-Time Type Identification(RTTI)。
总结: 向上转型是安全的,向下转型必须保证转型类型的一致性。
示例:
class Base {
int i=99;
public void amethod(){
System.out.println("Base.amethod()");
}
Base(){
amethod();
}
int getI(){return i;}
}
class Rt extends Base{
}
public class RType extends Base{
int i=-1;
public static void main(String argv[]){
Base b = new RType();
Base b1=new Base();
RType t=new RType();
//b1=t;
t=(RType)b1; //向下转型错误。b1实际上指向的是Base
t=(RType)b; //向下转型正确。
b.onlyyou(); //错误,Base类不提供onlyyou方法,尽管b实际上是RType
System.out.println(b.i);
System.out.println(b.getI());
b.amethod();
}
public void amethod(){
System.out.println("RType.amethod()");
}
int getI(){return i;}
public void onlyyou(){
}
}
Objective 2, Overriding and overloading
Write code to invoke overridden or overloaded methods and parental or overloaded constructors; and describe the effect of invoking these methods.
重载
如果同一个类中的多个方法有不同的参数列表,那么它们可以具有相同的名称。编译器在区分方法时不考虑返回类型,所以不能声明两个具有相同参数列表但返回类型不同的方法。
覆写与隐藏
如果子类中的一个实例方法与超类的一个实例方法具有相同的标记和返回类型,这被称为子类方法覆写了(override)超类方法。(记住,方法的标记包括它的名称,参数数量和参数类型)。子类覆写方法的能力允许从超类继承行为不同的 throws子句,但没有指定被覆写方法的throws子句没有指定的任何类型。
另外,覆写的方法的访问修饰符不能被被覆写的方法的访问修饰符严格,例如,超类中的保??的。子类不能覆写超类中的final方法。
子类必须覆写超类中声明为abstract的方法,否则子类本身必须是抽象的。
在编写与超类同名的方法时,分清是重载还是覆写,具有相同方法标记的是覆写,具有不同参数数量和类型的的是重载。
如果子类定义的类方法与超类的类方法具有相同的标记,那么子类方法隐藏超类的方法。
实例方法不能覆盖静态方法,而静态方法不能隐藏实例方法。
隐藏成员变量
在类中,如果一个成员变量与超类的成员变量同名(即使类型不同),那么它隐藏超类的成员变量。
在子类中,不能通过简单的名称引用超类的成员变量,而是必须通过super访问它。
示例:类的覆写与重载
class ClassA {
public int value=1;
public void methodOne(int i) {
System.out.println("ClassA methodOne");
}
public void methodTwo(int i) {
System.out.println("ClassA methodTwo");
}
public static void methodThree(int i) {
System.out.println("ClassA methodThree");
}
public static void methodFour(int i) {
System.out.println("ClassA methodFour");
}
int getValue(){return value;}
}
public class ClassB extends ClassA {
public double value=1.0;
public void methodOne(int i) {
System.out.println("ClassB methodOne");
}
public void methodTwo(int i) {
System.out.println("ClassB methodTwo");
}
public static void methodThree(int i) {
System.out.println("ClassA methodThree");
}
public static void methodFour(int i) {
System.out.println("ClassA methodFour");
}
public void methodFive(double value){
this.value=value;
System.out.println("value="+value);
System.out.println("super.value="+super.value);
}
public static void main(String[] args){
ClassA a=new ClassB();
a.methodOne(1);
a.methodThree(1);
ClassB b=(ClassB)a;
b.methodFive(2.0);
}
//double getValue(){return value;}
}
初始化与类的装载
Java的类加载方式:在java中每个类都在专属的.class文件中,这些文件只有在必要时才被装载。也就是说:“类程序代码在初次被使用时才被装载”。所谓的初次被使用,不仅是其第一个对象被建构之时,也可能是在某个static数据成员或static函数被取用时。“初次使用类”的时间点也是静态初始化进行的时机。
示例:关于类加载与初始化过程
class A{
int i;
A(int i){
this.i=i;
System.out.println("A constructor"+i);
}
A(){System.out.println("A constructor");}
static{
int i=7;
System.out.println("i="+i);
}
}
class Insect {
protected static A a=new A();
private int i = 9;
protected int j;
Insect() {
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
private static int x1 =
print("static Insect.x1 initialized");
static int print(String s) {
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect {
private int k = print("Beetle.k initialized");
private A a=new A();
public Beetle() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
private static int x2 =
print("static Beetle.x2 initialized");
public static void main(String[] args) {
System.out.println("Beetle constructor");
Beetle b = new Beetle();
}
}
分析上面程序的初始化过程:
程序的入口在Beetle.main()方法。程序执行时,类装载器被启动,找到Beetle.class并装载,由于Beetle类是Insect类的子类所以类装载器也将Insect.class装载。如果基类还要基类,这个过程将继续。
类加载完成后,将进行静态初始化过程,首先从根基类(Insect)开始,然后是其子类(Bettle),依次类推。在本例中,执行Insect 类中protected static A a=new A();类加载器装载A.class并进行静态初始化过程:A类中的static块,然后构造函数。然后,private static int x1 = print("static Insect.x1 initialized");最后是Beetle类中的private static int x2 = print("static Beetle.x2 initialized");
静态初始化完成后,将进行类实例的生成。首先,对象内的所有基本类型都会被评为设予缺省值,对象引用则被设予null.然后,基类的构造函数被唤起,缺省条件下基类的缺省构造函数被自动唤起,但你可用super(第一个运作)来调用基类的其它构造函数。执行Insect类的缺省函数。
基类构造完成后,是实例变量按次序被初始化,最后,才执行构造本体的剩余部分。
final类, 方法,变量
final变量是固定不变的数据。它可以:
可以是永不改变的编译期常量(compile-time constant)
可以是执行期(runtime)被初始化,而你不想再改变它。
final的对象引用的意义是它让引用保持不变而不是对象本身。某个引用一旦被初始化后,便再也不能指向另一个对象,但此对象本身的内容是可以改变的。
Java允许产生所谓的”blank finals”,也就是允许我们将数据成员声明为final,却不给予初值。注意:在任何情况下,blank finals必须在使用之间进行初始化, 而且编译器保证此事。所以,final的赋值运行如果不是发生在其定义处,就得在构造函数中以表达式设定其值。
final参数
?
final方法
final方法的原因: 第一:锁住这个函数,使子类不能改意其意义,即无法覆写;第二:效率。
类中的?在子类中隐藏,final函数却不能。
final类
final类就是说此类不能被继承。final类中的所有方法是final的但数据成员可是fianl也可不是fianl.
示? class Value {
int i; // Package access
public Value(int i) { this.i = i; }
private final void aMethod(){ //final??can be omitted
System.out.println("In Value.aMethod");
}
final void anotherMehtod(){
System.out.println("In Value.anotherMethod");
}
}
class SuperValue extends Value{
SuperValue(){super(1);}
void aMethod(){System.out.println("In SuperValue");}
//void anotherMethod(){} //final??method can not be changed
}
public class FinalData {
private static Random rand = new Random();
private String id;
public FinalData(String id,int j) { this.id = id; VAL_ONE=1; }
// Can be compile-time constants:
private final int VAL_ONE ; //bland final
private static final int VAL_TWO ;
static{
VAL_TWO=4;
}
// Typical public constant:
public static final int VAL_THREE = 39;
// Cannot be compile-time constants:
private final int i4 = rand.nextInt(20);
static final int i5 = rand.nextInt(20);
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
private static final Value v3 = new Value(33);
// Arrays:
private final int[] a = { 1, 2, 3, 4, 5, 6 };
public String toString() {
return id + ": " + "i4 = " + i4 + ", i5 = " + i5;
}
public static void main(String[] args) {
FinalData fd1 = new FinalData("fd1",9);
//! fd1.VAL_ONE++; // Error: can't change value
fd1.v2.i++; // Object isn't constant!
fd1.v1 = new Value(9); // OK -- not final
for(int i = 0; i < fd1.a.length; i++)
fd1.a++; // Object isn't constant!
//! fd1.v2 = new Value(0); // Error: Can't
//! fd1.v3 = new Value(1); // change reference
//! fd1.a = new int[3];
System.out.println(fd1);
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData("fd2",8);
System.out.println(fd1);
System.out.println(fd2);
Value v1=new SuperValue();
SuperValue v2=new SuperValue();
v2.aMethod();
//!v1.aMethod();
}
} ///:~
Objective 3, Creating class instances
Write code to construct instances of any concrete class including normal top level classes inner classes static inner classes and anonymous inner classes.
抽象类与抽象函数
抽象类是不能实例化的类,它定义了一组继承类的通用接口,继承类中所有的与抽象类标记相同的方法,会通过动态绑定的机制来调用。
抽象函数是一种不完全的函数,只有声明而无本体。具有抽象函数的类必须声明为abstract。
如果你要继承一个抽象类,你得实现抽象类中所有的抽象方法。否则,你的继承类也得声明为abstract.
不含任向abstract函数的类也可声明为抽象。
嵌套类(nested class)
嵌套类是另一个类的成员,反映了两个类之间的关系。当嵌套类只在包含它的类中有意义,或者它依赖于包含它的类来实现功能时,应该在另一个类中定义这个类。
嵌套类的特权: 它可以限制的访问包含它的类的成员,即使这些成员是私有的,嵌套类也可以访问它。
嵌套类可分为:静态嵌套类也称为(nested class)。非静态嵌套类也称为(inner class)
inner class
inner class不能具有任何static类型的data,fields,inner class.
匿名的inner类
只有用于实现事件接口。匿名inner类不能拥有构造函数。同时,匿名类一般与位于函数或Scopes内的类,所以它只接收外部的final数据。对匿名类的数据成员的初始化:一是在定义处,二是使用实体初始化(instance initialization).
示例: 匿名inner类
Section 7 Threads
Objective 1, Instantiating and starting threads
Write code to define, instantiate and start new threads using both java.lang.Thread and java.lang.Runnable
目标1 使用Thread类或Runnable接口定义,实例化和启动线程
什么是线程
线程是轻量级的进程,它能在主程序中并发执行。不同于进程,线程与进程中其它的线程共享内存与数据。
在JSCP考试中你要清楚一个概念:当程序启动了一个线程后,程序就有了多个执行路径。例如:线程A在线程B之前启动,这并不意味A必然先B执行完毕。程序的输出可能与底层的操作系统或系统中的已运行程序有关。
定义线程的两种方式
方式一:类实现Runnable接口
Runnable接口的定义:
public Interface Runnable{
public void run();
}
定义线程:
class MyClass implements Runnable{
public void run(){//Blank Body}
}
实例线程:
MyClass mc = new MyClass();
MyClass mc2 = new MyClass();
Thread t = new Thread(mc);
Thread t2 = new Thread(mc2);
t.start();
t2.start();
注意:实例实现Runnable接口线程,需要先实例Thread并将Runnable类作为构造器参数传递给Thread构造器。Thread的构造器方法之一:
Thread(Runnable target) 或者Thread(Runnable target, String name)
方式二: 类继承在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。注意: 这种方式直接明了但这也意味由于java只支持单一继承,所以你的子类不能再继承其它的类了。
定义线程
public class MyThread extends Thread {
public void run(){}
}
实例线程
MyThread t=new MyThread();
t.start();
实例化和启动线程
尽管线程的运行时做的事由run方法提供,但启动线程不是直接调用run方法,而是调用start方法。start方法分配运行线程所需的资源,调度线程运行,并调用线程的run方法。注意:你可以直接调用run方法,这时,run方法仅视为普通的方法而不是线程的一部分。
Although it is the run method code that executes, a thread is actually started via the start method.
示例:
public class Runt extends Thread{
public Runt(String name){
super(name);
}
public static void main(String argv[]){
for(int i=0;i<3;i++){
Runt r = new Runt(""+i);
r.run();
}
System.out.println("Begin To run concurrently");
for(int i=0;i<3;i++){
Runt r = new Runt(""+i);
r.start();
}
}
public void run(){
for(int i=0;i<10;i++)
System.out.println("# Thread-"+getName()+"-"+i);
}
}
Objective 2, When threads are prevented from executing
Recognise conditions that might prevent a thread from executing.
目标2 线程停止的原因
明确线程阻塞的条件
线程的四种状态
1. 新状态(New Thread):线程已被创建但尚未执行(start() 尚未被调用)。
2. 可执行状态(Runnable):线程可以执行,虽然不一定正在执行。CPU 时间随时可能被分配给该线程,从而使得它执行。
3. 死亡状态(Dead):正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果,但是不被推荐,前者会产生异常,后者是强制终止,不会释放锁。
4. 阻塞状态(Not Runnable):线程不会被分配 CPU 时间,无法执行。
线程阻塞的原因(Runnable->Not Runnable)
线程进入睡眠状态,那么必须经过指定的时间后线程返回可运行状态
线程由于调用wait而处于暂停状态,另一个对象调用了notfiy或notifyAll通知等待线程
线程由于IO操作而阻塞,IO完成后线程返回可运行状态
线程由于调用suspend()而阻塞,接到resume()后返回可运行状态(Deprecated)
sleep和wait/notify是引起阻塞的主要原因。
public static void sleep(long millis) throws InterruptedException
sleep方法是一个静态方法,它以以毫秒为单位的一段时间作为参数,使线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。注意:sleep方法抛出异常,在调用它时要捕捉这个异常。
线程的yield()方法(Running->Runnable)
public static void yield();
线程的yield方法使当前线程放弃对CPU资源的占用,线程进入Runable状态。由线程调度算法来选择其它Runnable线程runing.
操作系统的调度系统
时间片(Time Slicing)/抢占式(preemptive)
时间片系统将CPU分割为很短的时间段,并给每个具有相等而且最高优先级的线程分配时间段以供运行。时间片系统遍历具有相等且最高优先级的线程,允许它们各自运行一小段时间,直到其中一个或多个完成执行或一个具有更高优先级的线程抢占它们。Windows系统采用了抢占式调度。
非时间片(Non Time Slicing)/合作式(Cooperative)
由优先系统决定线程的运行,最高优先级的线程获得CPU时间。在这种机制下,程序要通过某种方式自动的放弃CPU时间。
示例:
public class SelfishRunner extends Thread {
private int tick = 1;
private int num;
public SelfishRunner(int num) {
this.num = num;
}
public void run() {
while (tick < 400000) {
tick++;
if ((tick % 50000) == 0){
System.out.println("Thread #" + num + ", tick = " + tick);
//yield(); //!自私的线程与公平的线程
}
}
}
}
public class RaceDemo {
private final static int NUMRUNNERS = 2;
public static void main(String[] args) {
SelfishRunner[] runners = new SelfishRunner[NUMRUNNERS];
for (int i = 0; i < NUMRUNNERS; i++) {
runners = new SelfishRunner(i);
runners.setPriority(2);
}
for (int i = 0; i < NUMRUNNERS; i++)
runners.start();
}
}
Objective 3, The wait/notify protocol
Write code using synchronized wait notify and notifyAll to protect against concurrent access problems and to communicate between threads. Define the interaction between threads and between threads and object locks when executing synchronized wait notify or notifyAll.
由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。这出就是线程同步的问题。
synchronized关键字
synchronzied关键字用于标识临界区(critical section)。临界区是单独的并发线程可访问期间的相同对象的代码段。它可以是一段代码或方法。名词Monitor,mutex(mutually exclusive lock)是指实现同步所需要的lock. Java平台将一个锁与每个具有同步代码的对象关联起来。当某个线程进入同步方法时,线程就锁定了此方法的对象。在对象被解锁前,其它线程不能调用??不是基于方法的。同步的方法的实现:
synchronized void amethod() { /* method body */}
或
synchronized (ObjectReference) { /* Block body */ }
When a synchronized block is executed, its object is locked and it cannot be called by any other code until the lock is freed.
wait/notify/notifyAll
public final void wait() throws InterruptedException
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout,int nanos) throws InterruptedException
public final void notify()
public final void notifyAll()
为了获得和释放lock,每个对象都能pause或wait,直到其它对象将锁转效到它。Wait/notify是线程间通信的一种方式。由于它们是Object类所具有的方法,所以在JAVA中所有的类都具有了线程通信的能力。调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。一对方法却必须在 synchronized 方法或块中调用,理由也很简单,只有在synchronized 方法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,这一对方法调用必须放置在这样的 synchronized 方法或块中,该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException 异常。如果没有notify方法,wait方法将毫无意义。因为它通知那些由于wait而阻塞的线程使它们能继续运行。
wait and notify should be placed within synchronized code to ensure that the current code owns the monitor
方法的使用
while(true){
try{
wait();
}catch (InterruptedException e) {}
}
//some producing action goes here
notifyAll();
注:notifyAll方法唤醒所有等待相关对象的线程。被唤醒的线程序争夺锁。一个线程得到锁,其它线程继续等待。notify方法,它任意唤醒等待此对象的线程之一。
示例:生产/消费者问题
public class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait();
} catch (InterruptedException e) { }
}
available = false;
notifyAll();
return contents;
}
public synchronized void put(int value) {
while (available == true) {
try {
wait();
} catch (InterruptedException e) { }
}
contents = value;
available = true;
notifyAll();
}
}
生产者
public class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" + this.number
+ " put: " + i);
try {
sleep((int)(Math.random() * 100));
Jason
2005-09-25 22:58:23
阅读:2546
评论:1
引用:0
来源:http://www.chinaitlab.com/www/news/article_show.asp?id=28661
Certification Key for SCJP1.4
Section 1 Declarations and Access Control
Objective 1, Creating Arrays
Write code that declares, constructs and initializes arrays of any base type using any of the permitted forms, both for declaration and for initialization
目标1, 创建数组
采用不同的格式来编写任一基本数据类型数组的声明,构造及初始化的代码。
数组是一连串对象或基本数据,它们必须同型,并以一个标识符封装在一起。数组好象一个对象,通过new关键字来创建。
声明数组
数组的声明并不能为数组分配内存。声明时数组不能有大小信息,也就是说编译器并不允许你告诉它究竟数组有多大,它只是一个reference(引用),并没有对应的空间。声明数组的方式有: int[] a1; int a1[]两种,int num[5]是错误的数组声明方式。
声明并创建数组
声明一个数组并同时为它分配内存。
Int num[] =new int[5];
声明并初始化数组
声明一个数组并同时进行初始化。
Int num[]=new int[]{0,1,2,3,4};
Int num[]=new int[5]{0,1,2,3,4}; //!错误
数组知道自己的大小
与c++不同,数组知道自己的大小,当数组越界时,会抛出ArrayIndexOutOfBoundsException异常。数组具有length属性(不是length()方法),它能告诉你数组的大小。
多维数据
int m[][] ; int [] m[]; int[][] m;
数组的缺省值
与其它的变量不同,不论数组在向处创建,它总是使用可以使用缺省值。
示例:
public class MyAr{
public static void main(String argv[]){
int[] i = new int[5];
int i[5]; //!编译错误
int[] m[]={{1,2,3,4},{2,3,4,5},{4,5,6,7}};
int[][] n={{1,2,3,4},{2,3,4,5},{4,5,6}};
int j;
m=n;
for(int k=0;k<n.length;k++){
System.out.println(n[k].length);
}
System.out.println(i[5]); //!运行错误,超界
System.out.println(i[4]); //正确,打印0
System.out.println(j); //!编译错误,没有初始化
For(int k=0;k<i.length;k++){
I[k]=k;
}
}
}
Objective 2, Declaring classes and variables
Declare classes, inner classes, methods, instance variables static, variables and automatic (method local) variables, making appropriate use of all permitted modifiers (such as public final static abstract and so forth). State the significance of each of these modifiers both singly and in combination and state the effect of package relationships on declared items qualified by these modifiers.
目标2 声明类与变量
声明类,内部类,方法,实例变量,静态变量,自动变量(局部变量),正确使用各种修饰符(public , private , static ,final, abstract)。
在JAVA中万事万物皆对象,即使JAVA程序本身也是对象。
类的定义和对象的生成
public class MyClass{ //类定义
int i;
float f; //类数据成员
void amethod(){ //方法
int i; // 局部变量
}
}
MyClass aClass =new MyClass(); //创建类的一个实例(对象)
修饰符说明
private
被了变量所在的类,其它任何类都不可以访问这个成员。
无访问修饰符
所谓的包访问权限,同一个包内的其它类可以访问这个成员。
Protected
与无访问修饰符具有权限外,还允许子类访问这个成员。
Public
具有全局可视性,任何其它类都可以访问这个成员。
Static
Static变量称为类变量,类的所有对象共享这个变量。
Static方法称为类方法,它只能访问static变量。静态方法不能被子类overriding为非静态方法,但静态方法可以被子类静态方法所Hided.
Native
只用于方法,指明方法体是由其它编程语言编写的。它以;结尾不是以{}结尾。
Public native void fastcalc();
Abstract
Abstract修饰符可用于类与方法前,在用于方法前时表明方法不具备方法体。只支类中包括了抽象方法则它必须声明为抽象类。如果一个类实现一个接口时,它没有为接口中所有的方法提供实现时,也必须声明为抽象类。
Final
Final修饰符可用于类,方法和变量,fianl类不能被继承,所有final类中的方法都是教学final方法。Final变量的值必须在创建时设定并具不能被修改。
Synchronized
防止多个线程同时访问相同的代码段。
Transient
表明类序列化时,变量不必序列化。
Volatile
表明变量由于线程可能异步修改。
示例:
abstract class Base{
abstract public void myfunc(); //抽象方法
public void another(){ //实例方法
System.out.println("Another method");
}
static void smethod(){ //类方法
System.out.println("base smethod");
}
}
public class Abs extends Base{
public static void main(String argv[]){
Abs a = new Abs();
Base b=new Abs();
a.amethod(); // 动态绑定,运行时调用
a.smethod(); //静态方法,编译时调用
b.smethod();
}
public void myfunc(){
System.out.println("My func");
}
public void amethod(){ //实现抽象方法
myfunc();
}
static void smethod(){ //hiding 父类静态方法
System.out.println("Abs smethod");
}
}
Objective 3, The default constructor
For a given class, determine if a default constructor will be created and if so state the prototype of that constructor
目标3 缺省构造器
结定一个类,确定是否有缺省构造器
构造器是与类名相同的方法,并具没有返回值。缺省构造器是一个不具有任何参数的构造器。在你没有提供构造器的条件下,编译器为自动化为你提供一个缺省的构造器,但一旦你定义了任何一个构造器,编译器就不会为你提供缺省构造器。在这种条件下,如果你使用不具有参数的构造器将有错误。
构造器可以有访问修饰符,但不能有native,abstract,static,synchronized和final修饰符。
示例:
class Base{
int i;
Base(int i){
this.i=i;
System.out.println("single int constructor");
}
void Base(){
System.out.println(“in void Base()”);
}
//Base(){}
}
public class Cons extends Base {
Cons(int i){}
//Cons(int i){super(i);}
public static void main(String argv[]){
Base c = new Base(); //编译错误,没有构造函数
Cons n=new Cons(3); //编译错误,Base没有无参数构造函数,void Base()函数不是构造函数。
}
}
Objective 4, Overloading and overriding
State the legal return types for any method given the declarations of all related methods in this or parent classes.
目标4 重载与覆写
为所有在自己或父类中的相关方法声明有效的返回值,
相同类中的方法
当在同一个类中有多个方法具有相同的名称时,这个方法就被重载了。只有参数的次序和类型是区分重载方法的依据,而返回值和参数的名称对区分重载方法没有贡献,所以,不能以返回值的不同来重载方法。
子类中的方法
可以在子类中重载父类的方法,只要新的重载方法具有不同的参数次序或类型。当你在子类中的方法具有于父类中的方法相同的signature,则称子类覆写了父类的方法。注意:子类覆写父类方法,它的访问修饰符可以不同,但子类要具有比父类更加严格的访问权限。
静态方法不能被覆写只能被HIDED。
基本类型为参数的重载
基本类型可以自动进行窄化转型(narrowing conversion),在没有相应数据类型的重载方法,它的数据类型向上晋升。
示例:
class Base{
public void another(int i){
System.out.println("Another int method"+i);
}
//public int another(int i){} //!编译错误,重复定义
public void another(double d){
System.out.println("Another double method "+d);
}
static void smethod(){
System.out.println("base smethod");
}
}
public class Abs extends Base{
public static void main(String argv[]){
Abs a = new Abs();
Base b=new Abs();
a.amethod();
a.smethod();
b.smethod();
a.another(4);
a.another(4.9f); // 注意:它调用了覆写方法
b.another(4.9f); // 它不调用覆写方法
}
public void myfunc(){
System.out.println("My func");
}
public void amethod(){
myfunc();
}
static void smethod(){
System.out.println("Abs smethod");
}
void another(float f){
System.out.println("Abs another float method"+f);
}
// void another(int i){ //编译错误,访问权限弱化
// System.out.println("Abs another method"+i);
// }
public void another(int i){
System.out.println("Abs another int method"+i);
}
}
Section 2 Flow control and exception Handling
Objective 1, The if and switch statements
Write code using if and switch statements and identify legal argument types for these statements.
目标1 if 和switch语句
使用if和switch编写代码并能区分有效的参数类型
if的条件语句中只能是boolean型的数据。
Int k=1;
If(k ) System.out.println(k); // 错误
If(k==1) System.out.println(k); // 正确
Switch的条件语句中只能是int数据类型,或int的窄化数据类型也就是byte, char, short
Long i;
Switch(i){ //错误
Case 1: .. break;
Case 2: … break;
Default: ..
}
case语句的break的使用,在switch块中只有遇到break语句时,块才跳出。
Default语句不必总安排在switch语句的最后,但default语句不在最后时,要使用break.
三元操作符 ?:
示例:
public class MySwitch{
public static void main(String argv[]){
MySwitch ms= new MySwitch();
ms.amethod();
ms.ifmethod();
}
public void amethod(){
byte k=30; // byte,char,short,int
switch(k){
default: //Put the default at the bottom, not here
System.out.println("This is the default output");
case 10:
System.out.println("ten"); break;
case 20:
System.out.println("twenty"); break;
}
}
public void ifmethod(){
int k=1;
boolean b;
//if(k=1) System.out.println("One");
if(k==1) System.out.println("one");
if(b=true) System.out.println("true");
}
}
输出结果:try it
Objective 2, looping, break and continue
Write code using all forms of loops including labeled and unlabeled use of break and continue and state the values taken by loop counter variables during and after loop execution.
目标2 循环,break和continue
编写各种(不)具有label的break和continue的循环语句。明确循环开始与结束时,循环记数器的值。
For 循环
语法:
for(initialization; conditional expression;increment)
逗号运算符
它只能用于for的控制表达式中。
for(int i=1,j=i+10;i<5;i++,j=i*2)
do-while与while的区别在开do-while中的语句至少执行一次。
Goto与break,continue
虽然goto是java的保留字,但java而不使用它。Java中的跳跃功能由break与continue提供。在java中,惟一一个放置lable而能够产生效益的地点就是恰恰放在迭代语句前。一般而论,break与continue只会中断当前的循环,而与label搭配,可以中断多层循环。
Label1:
Outeriteration{
Inneriteration{
…
break; //1
…
continue; //2
….
Continue label1;//3
….
Break label1; //4
}
}
1中断内层迭代,回到外层迭代
2将执行点移至内层迭代的起始处
3同时中断内层迭代,再从外层迭代开始
4同时中断内外层迭代,不再进行任何迭代
务必记下。在java中使用label的惟一理由是跳过一个以上的嵌套层次。
示例:
public class LabeledWhile {
public static void main(String[] args) {
int i = 0;
outer:
while(true) {
System.out.println("Outer while loop");
while(true) {
i++;
System.out.println("i = " + i);
if(i == 1) {
System.out.println("continue");
continue;
}
if(i == 3) {
System.out.println("continue outer");
continue outer;
}
if(i == 5) {
System.out.println("break");
break;
}
if(i == 7) {
System.out.println("break outer");
break outer;
}
}
}
}
}
输出结果: Just try it
Objective 3, try/catch and overridden methods
Write code that makes proper use of exceptions and exception handling clauses (try catch finally) and declares methods and overriding methods that throw exceptions.
目标3 try/catch语句与方法覆写
正确使用异常与异常处理语句(try,catch,finally)来编写代码,正确处理覆写方法的异常。
异常一词,意指“我对这件事有异议:我对这件事感到意外”。在问题发生点,你可能自己处理异常,有时,你可能不知道如向处理,就是说在当前的context并不具备中以修改问题的信息,你可将问题交付给高层的context的处理。
覆写有异常抛出的方法
覆写具的异常抛出的方法时,子类的方法只能抛出父类方法所抛出的异常或它的子异常。但是,子类方法可以抛出少于父类的异常或干脆就不抛异常。
方法声明的Throws子句
抛出子句意指当错误发生时,方法抛出这个异常而这个方法的调用者必须处理(catch)这个异常异常。
示例:
import java.io.*;
class Base{
public static void amethod()throws FileNotFoundException{}
public FileInputStream openFile(String filename)
throws FileNotFoundException{//抛出异常,自己不处理
FileInputStream fis = new FileInputStream(filename);
return fis;
}
}
public class ExcepDemo extends Base{
public static void main(String argv[]){
ExcepDemo e = new ExcepDemo();
try{ //调用者要处理抛出的异常
e.openFile("xx");
}catch(FileNotFoundException ex){
ex.printStackTrace();
}
}
public static void amethod(int i)throws IOException{} //overload
//public static void amethod() throws IOException{} //!编译错误 override
private boolean ExcepDemo(){ //不是构造方法
try{
DataInputStream din = new DataInputStream(System.in);
System.out.println("Pausing");
din.readChar();
System.out.println("Continuing");
this.amethod();
return true;
}catch(IOException ioe) {}
finally{
System.out.println("finally");
}
return false;
}
}
Objective 4, When Exceptions occur
Recognize the effect of an exception arising at a specified point in a code fragment. Note: The exception may be a runtime exception, a checked exception, or an error (the code may include try, catch, or finally clauses in any legitimate combination).
目标4 如时异常发生
认识代码段中异常发生的地方以它的影响。注意:异常可能是运行时异常,检测异常或错误。
错误无需捕捉
异常的出处:
Java标准库类抛出的异常
自己的类抛出的异常
执行期发生的任何意外
检测异常与非检测异常
检测异常你必须捕捉,而非检测异常你不必捕捉。
非检测异常发生后,缺省条件下会在控制台上打印一条消息。对某些非检测异常可用编码来避免。
public class GetArg{
public static void main(String argv[]){
if(argv.length ==0){
System.out.println("Usage: GetArg param");
}else{
System.out.println(argv[0]);
}
}
}
检测异常必须被捕捉,方法在调用某个抛出检测异常的的方法时,它或者捕捉它或抛出它。
public FileInputStream openFile(String filename)
throws FileNotFoundException{//抛出异常,自己不处理
FileInputStream fis = new FileInputStream(filename);
return fis;
}
或
public FileInputStream openFile(String filename) {
FileInputStream fis;
try{
fs= new FileInputStream(filename);
}catch(FileNotFoundException ex){
ex.printStackTrace();
}
return fis;
}
finally子句
finally子句总是会执行,即使try/catch中已有了return语句finally中的语句也会执行。但如果try/catch中有System.exit(0),finally语句不会执行。
Catch子句
Catch子句的捕捉异常的次序要与异常的层次结构相一致。也就是说子异常要先捕捉,父异常后捕捉。反之,编译器会抛出子异常已捕捉的信息。其它要注意是:异常被抛出后,异常处理根据捕捉的排列次序,寻找最近的处理程序。
示例:
class ThreeException extends Exception {}
class subException extends ThreeException{}
public class FinallyWorks {
static int count = 0;
public static void main(String[] args) {
while(true) {
try {
// Post-increment is zero first time:
if(count++ == 0)
throw new subException();
System.out.println("No exception");
/*} catch(subException e) { //catch的次序要如此,反之出错
System.err.println("ThreeException");*/
}catch(ThreeException e){
System.out.println(“subException”);
} finally {
System.err.println("In finally clause");
if(count == 2) break; // out of "while"
}
}
}
}
Objective 5 and 6 Using Assertions
Write code that makes proper use of assertions, and distinguish appropriate from inappropriate uses of assertions Identify correct statements about the assertion mechanism.
目标5 使用断言
正确编写断言代码
assertion功能提供了一种在代码中进行正确性检查的机制,这种检查通常用于开发和调试阶段,到了软件完成部署后就可以关闭。这使得程序员可以在代码中加入调试检查语句,同时又可以在软件部署后关闭该功能而避免对软件速度和内存消耗的影响。基本上,assertion功能就是JAVA中的一种新的错误检查机制,只不过这项功能可以根据需要关闭。
断言的语法
assert somebooleatest
或
assert somebooleantest : someinformatinvemethod
断言的使用
断言的使用就好比注释的使用,注释向其它人表明其阅读的代码是正确的,而断言用于保证在程序执行过程中booleanTest的值一定是真。断言用于确保某些东西总是为真的。缺省条件下,断言功能是关闭的。
编译开启断言功能。
javac -source1.4 Myprog.java
运行开启断言功能
enableassertions的参数:
no arguments
Enables or disables assertions in all classes except system classes.
packageName...
Enables or disables assertions in the named package and any subpackages.
...
Enables or disables assertions in the unnamed package in the current working directory.
className
Enables or disables assertions in the named class
例如:
java –enableassertions:my.package… MyProg
java –ea Myprog
What should you assert to be true?
断言用于你认为某此东西必须是真的地方。例如:人的年龄必然大于0,又如你认为在一套if/else判定后,必然有判定成功的分支,就可在if/else后,插入断言。例如:
switch(lang){
case Language.java:
System.out.println("java");
break;
case Language.pascal:
System.out.println("pascal");
break;
case Language.csharp:
System.out.println("csharp");
break;
default:
assert false : lang;
}
断言使用的地方
应该使用的情形 不应该使用的情形
用于保证内部数据结构的正确 不用于保证命令行参数的正确
用于保证私有(private)方法参数的正确 不用于保证公共(public)方法参数的正确
用于检查任何方法结束时状态的正确 不用于检查外界对公共方法的使用是否正确
用于检查决不应该出现的状态 不用于保证应该由用户提供的信息的正确性
用于检查决不应该出现的状态,即使你肯定它不会发生 不要用于代替if语句
用于在任何方法的开始检查相关的初始状态 不要用做外部控制条件
用于检查一个长循环执行过程中的的某些状态 不要用于检查编译器、操作系统、硬件的正确性,除非在调试过程中你有充分的理由相信它们有错误
示例:
class Language{
public static final int java=1;
public static final int pascal=2;
public static final int csharp=3;
}
public class Mgos {
static int lang=0;
static int age;
public static void setAge(int a){
assert age>0: “age must greater than zero”;
age=a;
}
public static void main(String argv[]){
setAge(-1);
switch(lang){
case Language.java:
System.out.println("java");
break;
case Language.pascal:
System.out.println("pascal");
break;
case Language.csharp:
System.out.println("csharp");
break;
default:
assert false : lang;
}
}
}
在不开启断言功能时的输出:
在开启断言功plicitly makes objects eligible for garbage collection. Recognize the point in a piece of source code at which an object becomes eligible for garbage collection.
为什么要进行垃圾收集
当内存中的对象不再被利用时,系统就要回收内存。Java中不用担心垃圾收集,系统的垃圾收集器会自动回收没有引用的对象所占用的内存。注意:你能建议或鼓励 JVM进行垃圾收集但你不能强迫它。
确保的行为:finalization
Java确保在对象被收集调用finalize方法。垃圾回收器用于释放“对象内存”,由于java中所有的东西都是对象,所以finalize不用来回收释放内存。Finalize方法的使用时机是代码采用了native方法,它调用了非java的内存分配方式,所以你得在finalize方法中以native的方式释放内存。
对象被回收的时机
当垃圾收集机制认为对象上没有引用时,它调用垃圾收集器来回收对象。当垃圾收集是非确定性的,你不能预测它发生的时间,你也不能预测finalize方法准确的运行时间。
Note: Once a variable is no longer referenced by anything it is available for garbage collection.
You can suggest garbage collection with System.gc(), but this does not guarantee when it will happen
非可达
当对象非可达时,就是可能进行回收。非可达的原因为:对象明确被设置为null或指向它的引用数为0。
示例:
public class RJMould{
StringBuffer sb;
public static void main(String argv[]){
RJMould rjm = new RJMould();
rjm.kansas();
}
public void kansas(){
sb = new StringBuffer("Manchester");
StringBuffer sb2 = sb;
StringBuffer sb3 = new StringBuffer("Chester");
sb=sb3;
sb3=null; // StringBuffer(“Chester”) is eligible for garbage collection
sb2=null; //StringBuffer("Manchester") is eligible for garbage collection
}
}
Section 4 Language Fundamentals
Objective 1, Packages, import, inner classes, interfaces
Identify correctly constructed package declarations, import statements, class declarations (of all forms including inner classes) interface declarations, method declarations (including the main method that is used to start execution of a class), variable declarations, and identifiers.
目标1 包,导入,内类与接口
正确的识别包声明,导入声明,类声明(包括内类),接口声明,方法声明(包括main方法),变量声明和修饰器。
包语句
包用于解决名字冲突,一般开发者以自己的internet域名的反序作为包名的第一部分。这样你就可以生成独一无二的包,这样包中的类就不会有名称上的冲突。例如:package cn.edu.xjtu.scjp 这样就可以产生独一无二的类名:cn.edu.xjtu.scjp.Question
注意: 包声明语句必须位于其它语句之前,除了注释语句
导入语句
导入语句位于包语句之后,其它语句之前。导入语句是为了方便代码编写,导入相应的包后,包中的类可以仅以局部名使用,而不以全限定名来使用。
Import cn.edu.xjtu.scjp.*;
Question q=new Question();
或
cn.edu.xjtu.scjp.Question q=new cn.edu.xjtu.scjp.Question();
导入语句对性能的没有影响,它就好比DOS环境中设置路径。
注意:If a source file has a package statement, it must come before any other statement apart from comments
类与内类的声明
类声明
一个文件只能包含一个public类,但可以包含多个非public类。这些类在编译后将生成各自独立的.class文件。
内类,即定义在其它类之中的类。
接口定义
接口是纯粹的abstract class.它所定义的方法不包含方法主体。接口也可定义数据成员,但这些数据成员自然而然的成为了static和final. 接口中的方法即使没有声明为public,它们也会是public,所以实现接口时,必须将实现的方法定义为public。
例子:
interface Instrument{
int i=5;// static & final
void play(); // automatically public
…
}
class Wind implments Instrument{
public void play(){} //必须定义为public
…
}
main方法
main方法是程序运行的起点,方法的signature
public static void main(String argv[])
public:方法全局可见性 static:类方法 void: 无返回值 String[]:参数为字符串数组
main不是java的关键字,可以用它来定义变量。Main方法的参数是由命令行来提供的。
State the correspondence between index values in the argument array passed to a main method and command line arguments.
Java Aclass arg0 arg1 …
变量声明
变量的名称:它必须是一个合法的标识符。标识符以字母开头的Unicode字符串;不是关键字,布尔直接值(true,false)或保留字(null);它在作用范围内必须是唯一的。
合法的变量: _avariable, avariable$, (注:_,$可用于变量名)
数据类型:boolean-8/1 byte-8 -128~127
short-16 -32768~32767 int-32 long-64
float-32 double-65 char-16 0~65536
数据类型转型(casting operators)
在java中只有进行窄化转换(narrowing conversion)时才有风险,宽化转化(widening conversion )时就无需明确指示。
数据运算中的晋升(promotion)
在比int小的基本数据类型上进行任何数学运算或位运算时,运算之前会先晋升为int,其结果也会是int类型。如果你要将结果指给较小的类型时,要进行转型。
示例:关于变量
class Variable{
int _aInt=4; // _,$可用于变量名
double _aDouble=4.0;
//!float _aFloat=6.0; //小数点直接数是double
float _aFloat=6.0f;
//!float $Float=2e3; //指数直接数是double
float $float=2e3f;
long $along=4;
byte _aByte=4;
short aShort=4;
byte $byte=0x04;
char _c='e';
char $c='\u0020';
void variableTest(){
//! _aByte=(byte)_aByte*$byte;//自动晋升
_aByte=(byte)(_aByte*$byte);
_aDouble=_aDouble/0.0;
_aFloat=_aFloat*$float;
System.out.println(_aFloat+" ;"+_aDouble);
_aDouble=_aInt;
_aInt=(int)_aDouble; //强制转换
//aShort=_c;
_aInt=_c;
}
public static void main(String[] args){
Variable v=new Variable();
v.variableTest();
}
}
Objective 2, Using interfaces
Identify classes that correctly implement an interface where that interface is either java.lang.Runnable or a fully specified interface in the question.
目标2 使用接口,
明确实现接口类,接口是Runnable或其它的用户自定义的接口
Interfaces -Programming by contract
接口是在类之间建立了一个协议(protocol),或者说合同编程。 意味一个开发者开发了接口其它开发者要守它的条件。接口的别一个用处是实现多重继承。Java中类只能继承一个非接口类,其余继承的来源得是接口。正确的写法是:
DeriveClass extends BaseClass implements interface1,interface2{}
接口合并时的名称冲突
Objective 3, Passing values from the command line
State the correspondence between index values in the argument array passed to a main method and command line arguments
运行一个例子就明白:
public class MyParm{
public static void main(String argv[]){
String s1 = argv[1];
System.out.println(s1);
}
}
java MyParm hello there
程序将输出there不是MyParm也不是hello
Objective 4, identify keywords
abstract boolean break byte case catch
char class const * continue default do
double else extends final finally float
for goto * if implements import instanceof
int interface long native new package
private protected public return short static
strictfp super switch synchronized this throw
throws transient try void volatile while
Objective 5, Unassigned variables
State the effect of using a variable or array element of any kind when no explicit assignment has been made to it.
Java保证变量绝对会在被使用前初始化。每个基本类型的数据成员都保证有初值(O)。而引用数据类型的数据成员的初值为null.
The default values for numeric types is zero, a boolean is false and an object reference is the only type that defaults to a null.
局部变量(在方法中定义的变量)不能缺省值,故使用前必须明确赋予初值。
数组总是可以设置缺省值的。Before initialization arrays are always set to contain default values wherever they are created.
Objective 6, The range and format of data types
Section 5 Operators and Assignments
Objective 1, Applying operators
Determine the result of applying any operator including assignment operators and instanceof to operands of any type class scope or accessibility or any combination of these.
目标1 使用运算符
操作符的分类
算术操作符 (+ , - , * , / , %,++,--)
一元操作符 (++, --, - , +)
关系和条件操作符 关系操作符(>,>=,<,<=,==,!=) 条件操作符(&&,||,!,&,|,^)
移位操作符(<<,>>,>>>) 位操作符(&,|,^,~)
赋值操作符(=)
其它操作符(?:,[],.,new,instanceof,(类型))
注:除了=,==,!=运算符外,其它运算符只能用于基本类型。String类支持+,+=操作符
例: String aStr=2+”hello”;
instanceof操作符用来检验某特殊对象是不是某类或该类的子类的实例,还可以检验某对象的类或子类是否实现了某接口。注意,数组也是对象,instanceof同样适合与数组。
Certification Key for SCJP1.4
Section 1 Declarations and Access Control
Objective 1, Creating Arrays
Write code that declares, constructs and initializes arrays of any base type using any of the permitted forms, both for declaration and for initialization
目标1, 创建数组
采用不同的格式来编写任一基本数据类型数组的声明,构造及初始化的代码。
数组是一连串对象或基本数据,它们必须同型,并以一个标识符封装在一起。数组好象一个对象,通过new关键字来创建。
声明数组
数组的声明并不能为数组分配内存。声明时数组不能有大小信息,也就是说编译器并不允许你告诉它究竟数组有多大,它只是一个reference(引用),并没有对应的空间。声明数组的方式有: int[] a1; int a1[]两种,int num[5]是错误的数组声明方式。
声明并创建数组
声明一个数组并同时为它分配内存。
Int num[] =new int[5];
声明并初始化数组
声明一个数组并同时进行初始化。
Int num[]=new int[]{0,1,2,3,4};
Int num[]=new int[5]{0,1,2,3,4}; //!错误
数组知道自己的大小
与c++不同,数组知道自己的大小,当数组越界时,会抛出ArrayIndexOutOfBoundsException异常。数组具有length属性(不是length()方法),它能告诉你数组的大小。
多维数据
int m[][] ; int [] m[]; int[][] m;
数组的缺省值
与其它的变量不同,不论数组在向处创建,它总是使用可以使用缺省值。
示例:
public class MyAr{
public static void main(String argv[]){
int[] i = new int[5];
int i[5]; //!编译错误
int[] m[]={{1,2,3,4},{2,3,4,5},{4,5,6,7}};
int[][] n={{1,2,3,4},{2,3,4,5},{4,5,6}};
int j;
m=n;
for(int k=0;k<n.length;k++){
System.out.println(n[k].length);
}
System.out.println(i[5]); //!运行错误,超界
System.out.println(i[4]); //正确,打印0
System.out.println(j); //!编译错误,没有初始化
For(int k=0;k<i.length;k++){
I[k]=k;
}
}
}
Objective 2, Declaring classes and variables
Declare classes, inner classes, methods, instance variables static, variables and automatic (method local) variables, making appropriate use of all permitted modifiers (such as public final static abstract and so forth). State the significance of each of these modifiers both singly and in combination and state the effect of package relationships on declared items qualified by these modifiers.
目标2 声明类与变量
声明类,内部类,方法,实例变量,静态变量,自动变量(局部变量),正确使用各种修饰符(public , private , static ,final, abstract)。
在JAVA中万事万物皆对象,即使JAVA程序本身也是对象。
类的定义和对象的生成
public class MyClass{ //类定义
int i;
float f; //类数据成员
void amethod(){ //方法
int i; // 局部变量
}
}
MyClass aClass =new MyClass(); //创建类的一个实例(对象)
修饰符说明
private
被了变量所在的类,其它任何类都不可以访问这个成员。
无访问修饰符
所谓的包访问权限,同一个包内的其它类可以访问这个成员。
Protected
与无访问修饰符具有权限外,还允许子类访问这个成员。
Public
具有全局可视性,任何其它类都可以访问这个成员。
Static
Static变量称为类变量,类的所有对象共享这个变量。
Static方法称为类方法,它只能访问static变量。静态方法不能被子类overriding为非静态方法,但静态方法可以被子类静态方法所Hided.
Native
只用于方法,指明方法体是由其它编程语言编写的。它以;结尾不是以{}结尾。
Public native void fastcalc();
Abstract
Abstract修饰符可用于类与方法前,在用于方法前时表明方法不具备方法体。只支类中包括了抽象方法则它必须声明为抽象类。如果一个类实现一个接口时,它没有为接口中所有的方法提供实现时,也必须声明为抽象类。
Final
Final修饰符可用于类,方法和变量,fianl类不能被继承,所有final类中的方法都是教学final方法。Final变量的值必须在创建时设定并具不能被修改。
Synchronized
防止多个线程同时访问相同的代码段。
Transient
表明类序列化时,变量不必序列化。
Volatile
表明变量由于线程可能异步修改。
示例:
abstract class Base{
abstract public void myfunc(); //抽象方法
public void another(){ //实例方法
System.out.println("Another method");
}
static void smethod(){ //类方法
System.out.println("base smethod");
}
}
public class Abs extends Base{
public static void main(String argv[]){
Abs a = new Abs();
Base b=new Abs();
a.amethod(); // 动态绑定,运行时调用
a.smethod(); //静态方法,编译时调用
b.smethod();
}
public void myfunc(){
System.out.println("My func");
}
public void amethod(){ //实现抽象方法
myfunc();
}
static void smethod(){ //hiding 父类静态方法
System.out.println("Abs smethod");
}
}
Objective 3, The default constructor
For a given class, determine if a default constructor will be created and if so state the prototype of that constructor
目标3 缺省构造器
结定一个类,确定是否有缺省构造器
构造器是与类名相同的方法,并具没有返回值。缺省构造器是一个不具有任何参数的构造器。在你没有提供构造器的条件下,编译器为自动化为你提供一个缺省的构造器,但一旦你定义了任何一个构造器,编译器就不会为你提供缺省构造器。在这种条件下,如果你使用不具有参数的构造器将有错误。
构造器可以有访问修饰符,但不能有native,abstract,static,synchronized和final修饰符。
示例:
class Base{
int i;
Base(int i){
this.i=i;
System.out.println("single int constructor");
}
void Base(){
System.out.println(“in void Base()”);
}
//Base(){}
}
public class Cons extends Base {
Cons(int i){}
//Cons(int i){super(i);}
public static void main(String argv[]){
Base c = new Base(); //编译错误,没有构造函数
Cons n=new Cons(3); //编译错误,Base没有无参数构造函数,void Base()函数不是构造函数。
}
}
Objective 4, Overloading and overriding
State the legal return types for any method given the declarations of all related methods in this or parent classes.
目标4 重载与覆写
为所有在自己或父类中的相关方法声明有效的返回值,
相同类中的方法
当在同一个类中有多个方法具有相同的名称时,这个方法就被重载了。只有参数的次序和类型是区分重载方法的依据,而返回值和参数的名称对区分重载方法没有贡献,所以,不能以返回值的不同来重载方法。
子类中的方法
可以在子类中重载父类的方法,只要新的重载方法具有不同的参数次序或类型。当你在子类中的方法具有于父类中的方法相同的signature,则称子类覆写了父类的方法。注意:子类覆写父类方法,它的访问修饰符可以不同,但子类要具有比父类更加严格的访问权限。
静态方法不能被覆写只能被HIDED。
基本类型为参数的重载
基本类型可以自动进行窄化转型(narrowing conversion),在没有相应数据类型的重载方法,它的数据类型向上晋升。
示例:
class Base{
public void another(int i){
System.out.println("Another int method"+i);
}
//public int another(int i){} //!编译错误,重复定义
public void another(double d){
System.out.println("Another double method "+d);
}
static void smethod(){
System.out.println("base smethod");
}
}
public class Abs extends Base{
public static void main(String argv[]){
Abs a = new Abs();
Base b=new Abs();
a.amethod();
a.smethod();
b.smethod();
a.another(4);
a.another(4.9f); // 注意:它调用了覆写方法
b.another(4.9f); // 它不调用覆写方法
}
public void myfunc(){
System.out.println("My func");
}
public void amethod(){
myfunc();
}
static void smethod(){
System.out.println("Abs smethod");
}
void another(float f){
System.out.println("Abs another float method"+f);
}
// void another(int i){ //编译错误,访问权限弱化
// System.out.println("Abs another method"+i);
// }
public void another(int i){
System.out.println("Abs another int method"+i);
}
}
Section 2 Flow control and exception Handling
Objective 1, The if and switch statements
Write code using if and switch statements and identify legal argument types for these statements.
目标1 if 和switch语句
使用if和switch编写代码并能区分有效的参数类型
if的条件语句中只能是boolean型的数据。
Int k=1;
If(k ) System.out.println(k); // 错误
If(k==1) System.out.println(k); // 正确
Switch的条件语句中只能是int数据类型,或int的窄化数据类型也就是byte, char, short
Long i;
Switch(i){ //错误
Case 1: .. break;
Case 2: … break;
Default: ..
}
case语句的break的使用,在switch块中只有遇到break语句时,块才跳出。
Default语句不必总安排在switch语句的最后,但default语句不在最后时,要使用break.
三元操作符 ?:
示例:
public class MySwitch{
public static void main(String argv[]){
MySwitch ms= new MySwitch();
ms.amethod();
ms.ifmethod();
}
public void amethod(){
byte k=30; // byte,char,short,int
switch(k){
default: //Put the default at the bottom, not here
System.out.println("This is the default output");
case 10:
System.out.println("ten"); break;
case 20:
System.out.println("twenty"); break;
}
}
public void ifmethod(){
int k=1;
boolean b;
//if(k=1) System.out.println("One");
if(k==1) System.out.println("one");
if(b=true) System.out.println("true");
}
}
输出结果:try it
Objective 2, looping, break and continue
Write code using all forms of loops including labeled and unlabeled use of break and continue and state the values taken by loop counter variables during and after loop execution.
目标2 循环,break和continue
编写各种(不)具有label的break和continue的循环语句。明确循环开始与结束时,循环记数器的值。
For 循环
语法:
for(initialization; conditional expression;increment)
逗号运算符
它只能用于for的控制表达式中。
for(int i=1,j=i+10;i<5;i++,j=i*2)
do-while与while的区别在开do-while中的语句至少执行一次。
Goto与break,continue
虽然goto是java的保留字,但java而不使用它。Java中的跳跃功能由break与continue提供。在java中,惟一一个放置lable而能够产生效益的地点就是恰恰放在迭代语句前。一般而论,break与continue只会中断当前的循环,而与label搭配,可以中断多层循环。
Label1:
Outeriteration{
Inneriteration{
…
break; //1
…
continue; //2
….
Continue label1;//3
….
Break label1; //4
}
}
1中断内层迭代,回到外层迭代
2将执行点移至内层迭代的起始处
3同时中断内层迭代,再从外层迭代开始
4同时中断内外层迭代,不再进行任何迭代
务必记下。在java中使用label的惟一理由是跳过一个以上的嵌套层次。
示例:
public class LabeledWhile {
public static void main(String[] args) {
int i = 0;
outer:
while(true) {
System.out.println("Outer while loop");
while(true) {
i++;
System.out.println("i = " + i);
if(i == 1) {
System.out.println("continue");
continue;
}
if(i == 3) {
System.out.println("continue outer");
continue outer;
}
if(i == 5) {
System.out.println("break");
break;
}
if(i == 7) {
System.out.println("break outer");
break outer;
}
}
}
}
}
输出结果: Just try it
Objective 3, try/catch and overridden methods
Write code that makes proper use of exceptions and exception handling clauses (try catch finally) and declares methods and overriding methods that throw exceptions.
目标3 try/catch语句与方法覆写
正确使用异常与异常处理语句(try,catch,finally)来编写代码,正确处理覆写方法的异常。
异常一词,意指“我对这件事有异议:我对这件事感到意外”。在问题发生点,你可能自己处理异常,有时,你可能不知道如向处理,就是说在当前的context并不具备中以修改问题的信息,你可将问题交付给高层的context的处理。
覆写有异常抛出的方法
覆写具的异常抛出的方法时,子类的方法只能抛出父类方法所抛出的异常或它的子异常。但是,子类方法可以抛出少于父类的异常或干脆就不抛异常。
方法声明的Throws子句
抛出子句意指当错误发生时,方法抛出这个异常而这个方法的调用者必须处理(catch)这个异常异常。
示例:
import java.io.*;
class Base{
public static void amethod()throws FileNotFoundException{}
public FileInputStream openFile(String filename)
throws FileNotFoundException{//抛出异常,自己不处理
FileInputStream fis = new FileInputStream(filename);
return fis;
}
}
public class ExcepDemo extends Base{
public static void main(String argv[]){
ExcepDemo e = new ExcepDemo();
try{ //调用者要处理抛出的异常
e.openFile("xx");
}catch(FileNotFoundException ex){
ex.printStackTrace();
}
}
public static void amethod(int i)throws IOException{} //overload
//public static void amethod() throws IOException{} //!编译错误 override
private boolean ExcepDemo(){ //不是构造方法
try{
DataInputStream din = new DataInputStream(System.in);
System.out.println("Pausing");
din.readChar();
System.out.println("Continuing");
this.amethod();
return true;
}catch(IOException ioe) {}
finally{
System.out.println("finally");
}
return false;
}
}
Objective 4, When Exceptions occur
Recognize the effect of an exception arising at a specified point in a code fragment. Note: The exception may be a runtime exception, a checked exception, or an error (the code may include try, catch, or finally clauses in any legitimate combination).
目标4 如时异常发生
认识代码段中异常发生的地方以它的影响。注意:异常可能是运行时异常,检测异常或错误。
错误无需捕捉
异常的出处:
Java标准库类抛出的异常
自己的类抛出的异常
执行期发生的任何意外
检测异常与非检测异常
检测异常你必须捕捉,而非检测异常你不必捕捉。
非检测异常发生后,缺省条件下会在控制台上打印一条消息。对某些非检测异常可用编码来避免。
public class GetArg{
public static void main(String argv[]){
if(argv.length ==0){
System.out.println("Usage: GetArg param");
}else{
System.out.println(argv[0]);
}
}
}
检测异常必须被捕捉,方法在调用某个抛出检测异常的的方法时,它或者捕捉它或抛出它。
public FileInputStream openFile(String filename)
throws FileNotFoundException{//抛出异常,自己不处理
FileInputStream fis = new FileInputStream(filename);
return fis;
}
或
public FileInputStream openFile(String filename) {
FileInputStream fis;
try{
fs= new FileInputStream(filename);
}catch(FileNotFoundException ex){
ex.printStackTrace();
}
return fis;
}
finally子句
finally子句总是会执行,即使try/catch中已有了return语句finally中的语句也会执行。但如果try/catch中有System.exit(0),finally语句不会执行。
Catch子句
Catch子句的捕捉异常的次序要与异常的层次结构相一致。也就是说子异常要先捕捉,父异常后捕捉。反之,编译器会抛出子异常已捕捉的信息。其它要注意是:异常被抛出后,异常处理根据捕捉的排列次序,寻找最近的处理程序。
示例:
class ThreeException extends Exception {}
class subException extends ThreeException{}
public class FinallyWorks {
static int count = 0;
public static void main(String[] args) {
while(true) {
try {
// Post-increment is zero first time:
if(count++ == 0)
throw new subException();
System.out.println("No exception");
/*} catch(subException e) { //catch的次序要如此,反之出错
System.err.println("ThreeException");*/
}catch(ThreeException e){
System.out.println(“subException”);
} finally {
System.err.println("In finally clause");
if(count == 2) break; // out of "while"
}
}
}
}
Objective 5 and 6 Using Assertions
Write code that makes proper use of assertions, and distinguish appropriate from inappropriate uses of assertions Identify correct statements about the assertion mechanism.
目标5 使用断言
正确编写断言代码
assertion功能提供了一种在代码中进行正确性检查的机制,这种检查通常用于开发和调试阶段,到了软件完成部署后就可以关闭。这使得程序员可以在代码中加入调试检查语句,同时又可以在软件部署后关闭该功能而避免对软件速度和内存消耗的影响。基本上,assertion功能就是JAVA中的一种新的错误检查机制,只不过这项功能可以根据需要关闭。
断言的语法
assert somebooleatest
或
assert somebooleantest : someinformatinvemethod
断言的使用
断言的使用就好比注释的使用,注释向其它人表明其阅读的代码是正确的,而断言用于保证在程序执行过程中booleanTest的值一定是真。断言用于确保某些东西总是为真的。缺省条件下,断言功能是关闭的。
编译开启断言功能。
javac -source1.4 Myprog.java
运行开启断言功能
enableassertions的参数:
no arguments
Enables or disables assertions in all classes except system classes.
packageName...
Enables or disables assertions in the named package and any subpackages.
...
Enables or disables assertions in the unnamed package in the current working directory.
className
Enables or disables assertions in the named class
例如:
java –enableassertions:my.package… MyProg
java –ea Myprog
What should you assert to be true?
断言用于你认为某此东西必须是真的地方。例如:人的年龄必然大于0,又如你认为在一套if/else判定后,必然有判定成功的分支,就可在if/else后,插入断言。例如:
switch(lang){
case Language.java:
System.out.println("java");
break;
case Language.pascal:
System.out.println("pascal");
break;
case Language.csharp:
System.out.println("csharp");
break;
default:
assert false : lang;
}
断言使用的地方
应该使用的情形 不应该使用的情形
用于保证内部数据结构的正确 不用于保证命令行参数的正确
用于保证私有(private)方法参数的正确 不用于保证公共(public)方法参数的正确
用于检查任何方法结束时状态的正确 不用于检查外界对公共方法的使用是否正确
用于检查决不应该出现的状态 不用于保证应该由用户提供的信息的正确性
用于检查决不应该出现的状态,即使你肯定它不会发生 不要用于代替if语句
用于在任何方法的开始检查相关的初始状态 不要用做外部控制条件
用于检查一个长循环执行过程中的的某些状态 不要用于检查编译器、操作系统、硬件的正确性,除非在调试过程中你有充分的理由相信它们有错误
示例:
class Language{
public static final int java=1;
public static final int pascal=2;
public static final int csharp=3;
}
public class Mgos {
static int lang=0;
static int age;
public static void setAge(int a){
assert age>0: “age must greater than zero”;
age=a;
}
public static void main(String argv[]){
setAge(-1);
switch(lang){
case Language.java:
System.out.println("java");
break;
case Language.pascal:
System.out.println("pascal");
break;
case Language.csharp:
System.out.println("csharp");
break;
default:
assert false : lang;
}
}
}
在不开启断言功能时的输出:
在开启断言功plicitly makes objects eligible for garbage collection. Recognize the point in a piece of source code at which an object becomes eligible for garbage collection.
为什么要进行垃圾收集
当内存中的对象不再被利用时,系统就要回收内存。Java中不用担心垃圾收集,系统的垃圾收集器会自动回收没有引用的对象所占用的内存。注意:你能建议或鼓励 JVM进行垃圾收集但你不能强迫它。
确保的行为:finalization
Java确保在对象被收集调用finalize方法。垃圾回收器用于释放“对象内存”,由于java中所有的东西都是对象,所以finalize不用来回收释放内存。Finalize方法的使用时机是代码采用了native方法,它调用了非java的内存分配方式,所以你得在finalize方法中以native的方式释放内存。
对象被回收的时机
当垃圾收集机制认为对象上没有引用时,它调用垃圾收集器来回收对象。当垃圾收集是非确定性的,你不能预测它发生的时间,你也不能预测finalize方法准确的运行时间。
Note: Once a variable is no longer referenced by anything it is available for garbage collection.
You can suggest garbage collection with System.gc(), but this does not guarantee when it will happen
非可达
当对象非可达时,就是可能进行回收。非可达的原因为:对象明确被设置为null或指向它的引用数为0。
示例:
public class RJMould{
StringBuffer sb;
public static void main(String argv[]){
RJMould rjm = new RJMould();
rjm.kansas();
}
public void kansas(){
sb = new StringBuffer("Manchester");
StringBuffer sb2 = sb;
StringBuffer sb3 = new StringBuffer("Chester");
sb=sb3;
sb3=null; // StringBuffer(“Chester”) is eligible for garbage collection
sb2=null; //StringBuffer("Manchester") is eligible for garbage collection
}
}
Section 4 Language Fundamentals
Objective 1, Packages, import, inner classes, interfaces
Identify correctly constructed package declarations, import statements, class declarations (of all forms including inner classes) interface declarations, method declarations (including the main method that is used to start execution of a class), variable declarations, and identifiers.
目标1 包,导入,内类与接口
正确的识别包声明,导入声明,类声明(包括内类),接口声明,方法声明(包括main方法),变量声明和修饰器。
包语句
包用于解决名字冲突,一般开发者以自己的internet域名的反序作为包名的第一部分。这样你就可以生成独一无二的包,这样包中的类就不会有名称上的冲突。例如:package cn.edu.xjtu.scjp 这样就可以产生独一无二的类名:cn.edu.xjtu.scjp.Question
注意: 包声明语句必须位于其它语句之前,除了注释语句
导入语句
导入语句位于包语句之后,其它语句之前。导入语句是为了方便代码编写,导入相应的包后,包中的类可以仅以局部名使用,而不以全限定名来使用。
Import cn.edu.xjtu.scjp.*;
Question q=new Question();
或
cn.edu.xjtu.scjp.Question q=new cn.edu.xjtu.scjp.Question();
导入语句对性能的没有影响,它就好比DOS环境中设置路径。
注意:If a source file has a package statement, it must come before any other statement apart from comments
类与内类的声明
类声明
一个文件只能包含一个public类,但可以包含多个非public类。这些类在编译后将生成各自独立的.class文件。
内类,即定义在其它类之中的类。
接口定义
接口是纯粹的abstract class.它所定义的方法不包含方法主体。接口也可定义数据成员,但这些数据成员自然而然的成为了static和final. 接口中的方法即使没有声明为public,它们也会是public,所以实现接口时,必须将实现的方法定义为public。
例子:
interface Instrument{
int i=5;// static & final
void play(); // automatically public
…
}
class Wind implments Instrument{
public void play(){} //必须定义为public
…
}
main方法
main方法是程序运行的起点,方法的signature
public static void main(String argv[])
public:方法全局可见性 static:类方法 void: 无返回值 String[]:参数为字符串数组
main不是java的关键字,可以用它来定义变量。Main方法的参数是由命令行来提供的。
State the correspondence between index values in the argument array passed to a main method and command line arguments.
Java Aclass arg0 arg1 …
变量声明
变量的名称:它必须是一个合法的标识符。标识符以字母开头的Unicode字符串;不是关键字,布尔直接值(true,false)或保留字(null);它在作用范围内必须是唯一的。
合法的变量: _avariable, avariable$, (注:_,$可用于变量名)
数据类型:boolean-8/1 byte-8 -128~127
short-16 -32768~32767 int-32 long-64
float-32 double-65 char-16 0~65536
数据类型转型(casting operators)
在java中只有进行窄化转换(narrowing conversion)时才有风险,宽化转化(widening conversion )时就无需明确指示。
数据运算中的晋升(promotion)
在比int小的基本数据类型上进行任何数学运算或位运算时,运算之前会先晋升为int,其结果也会是int类型。如果你要将结果指给较小的类型时,要进行转型。
示例:关于变量
class Variable{
int _aInt=4; // _,$可用于变量名
double _aDouble=4.0;
//!float _aFloat=6.0; //小数点直接数是double
float _aFloat=6.0f;
//!float $Float=2e3; //指数直接数是double
float $float=2e3f;
long $along=4;
byte _aByte=4;
short aShort=4;
byte $byte=0x04;
char _c='e';
char $c='\u0020';
void variableTest(){
//! _aByte=(byte)_aByte*$byte;//自动晋升
_aByte=(byte)(_aByte*$byte);
_aDouble=_aDouble/0.0;
_aFloat=_aFloat*$float;
System.out.println(_aFloat+" ;"+_aDouble);
_aDouble=_aInt;
_aInt=(int)_aDouble; //强制转换
//aShort=_c;
_aInt=_c;
}
public static void main(String[] args){
Variable v=new Variable();
v.variableTest();
}
}
Objective 2, Using interfaces
Identify classes that correctly implement an interface where that interface is either java.lang.Runnable or a fully specified interface in the question.
目标2 使用接口,
明确实现接口类,接口是Runnable或其它的用户自定义的接口
Interfaces -Programming by contract
接口是在类之间建立了一个协议(protocol),或者说合同编程。 意味一个开发者开发了接口其它开发者要守它的条件。接口的别一个用处是实现多重继承。Java中类只能继承一个非接口类,其余继承的来源得是接口。正确的写法是:
DeriveClass extends BaseClass implements interface1,interface2{}
接口合并时的名称冲突
Objective 3, Passing values from the command line
State the correspondence between index values in the argument array passed to a main method and command line arguments
运行一个例子就明白:
public class MyParm{
public static void main(String argv[]){
String s1 = argv[1];
System.out.println(s1);
}
}
java MyParm hello there
程序将输出there不是MyParm也不是hello
Objective 4, identify keywords
abstract boolean break byte case catch
char class const * continue default do
double else extends final finally float
for goto * if implements import instanceof
int interface long native new package
private protected public return short static
strictfp super switch synchronized this throw
throws transient try void volatile while
Objective 5, Unassigned variables
State the effect of using a variable or array element of any kind when no explicit assignment has been made to it.
Java保证变量绝对会在被使用前初始化。每个基本类型的数据成员都保证有初值(O)。而引用数据类型的数据成员的初值为null.
The default values for numeric types is zero, a boolean is false and an object reference is the only type that defaults to a null.
局部变量(在方法中定义的变量)不能缺省值,故使用前必须明确赋予初值。
数组总是可以设置缺省值的。Before initialization arrays are always set to contain default values wherever they are created.
Objective 6, The range and format of data types
Section 5 Operators and Assignments
Objective 1, Applying operators
Determine the result of applying any operator including assignment operators and instanceof to operands of any type class scope or accessibility or any combination of these.
目标1 使用运算符
操作符的分类
算术操作符 (+ , - , * , / , %,++,--)
一元操作符 (++, --, - , +)
关系和条件操作符 关系操作符(>,>=,<,<=,==,!=) 条件操作符(&&,||,!,&,|,^)
移位操作符(<<,>>,>>>) 位操作符(&,|,^,~)
赋值操作符(=)
其它操作符(?:,[],.,new,instanceof,(类型))
注:除了=,==,!=运算符外,其它运算符只能用于基本类型。String类支持+,+=操作符
例: String aStr=2+”hello”;
instanceof操作符用来检验某特殊对象是不是某类或该类的子类的实例,还可以检验某对象的类或子类是否实现了某接口。注意,数组也是对象,instanceof同样适合与数组。
Jason
2005-09-25 22:58:08
阅读:2704
评论:0
引用:0
来源:http://www.chinaitlab.com/www/news/article_show.asp?id=25618
第一部分:声明和访问控制
声明,构建,初始化任何类型的数组
声明类,内部类,方法,成员变量,静态成员变量和方法变量,并会应用任何合法的修饰符(如public,final,static,abstract,等等)。能够
明了这些修饰符单独和组合起来的含义,并且知道被修饰符修饰的任意对象在各种包相关联系下的影响。
第二部分:流程控制,断言和异常处理
能够正确使用if,switch语句并且在这些语句中能正确使用合法的参数类型。
能够正确使用所有带标签或不带标签的循环语句,能使用break,continue,能计算在循环中或循环后循环计数器的值。
能够正确使用异常和异常处理语句(try,catch,finally)。能正确声明掷出例外的方法,并知道怎样覆盖它。
知道在程序段的特定点出现的异常对程序的影响。即:异常可能是一个runtime exception,一个checked exception也可能是一个error。(这
个程序段可能包括try,catch,finally并以任何可能的合法组合出现。)。
能正确应用断言,区分正确使用的断言和不正确的。
明白关于断言机制的正确说法。
第三部分:垃圾收集
明白垃圾收集机制确定性的行为。
能用程序显式的使一个对象能被垃圾收集器合法的收集。
知道在程序的哪一点垃圾收集器能合法地收集一个对象。
第四部分:语言基础
能正确构建包声明,import声明,类声明(包括内部类),接口声明,方法声明(包括用于开始一个类的执行的main方法),变量声明及其其
它的一些说明符。
能够正确使用一些类,这些类要么实现了java.lang.Runnable这个接口,要么能正确实现在问题中构建的一些接口。
知道传入main函数的命令行参数的index value。
知道所有JAVA的keyword。注意:考试中不会出现要你区分keyword和各种常数这类深奥的问题。
明白如果没有显式地赋值的各种变量或者数组被使用会出现什么结果。
知道所有原始数据类型的取值范围,怎样声明一个String的字面值等等。
第五部分:操作与赋值
能知道当任何操作符(包括赋值操作符和intanceof操作符)应用于任何操作数(任何类型的类或访问能力或两者的任意组合)的结果。
知道String,Boolean和Object类使用equals(Object)方法后的结果。
知道当对已经知道值的变量进行&,|,&&,||操作时,哪些操作数被运算了,表达式最终的结果是怎样的。
知道Object和原始类型数据传入方法的不同方式,知道如何在这些方法中如何进行赋值或其它修改操作。
第六部分:覆盖,重载,运行时期类型及其面向对象
知道面向对象设计中封装的好处并能用程序实现紧密封装的类,能知道is a和has a的意义。
能正确使用覆盖和重载的方法,能正确调用父类或覆盖了的构建器,知道调用这些方法后的结果。
能实例化任何具体的一般顶层类和内部类。
第七部分:线程
能用java.lang,Thread和java.lang.Runnable两种方法定义,实例化和开始一个新的线程。
知道哪些情况下可能阻止一个线程的执行。
能使用synchronized,wait,notify和notifyAll去解决避免同时访问及其线程间相互通讯的问题。
当执行synchronized,wait,notify和notifyAll时,知道线程和对象锁之间的交互作用。
第八部分:在java.lang包中的基础类
能够应用Math类中的abs,ceil,floor,max,min,random,round,sin,cos,tan,sqrt方法。
正确描述String类不可改变的意义。
当执行一段程序,中间包含有wrapper类的一个实例,知道它运行的前提条件运行结果。能用下面wrapper类(例如Integer,Double,等等)的方
法来写程序:
doublevalue
floatvalue
intvalue
longvalue
parseXxx
getXxx
toString
toHexString
第九部分:集合类框架
知道如何在特定的条件下选择适合的集合类/接口。
区分正确和不正确对hashcode方法的实现。
第一部分:声明和访问控制
声明,构建,初始化任何类型的数组
声明类,内部类,方法,成员变量,静态成员变量和方法变量,并会应用任何合法的修饰符(如public,final,static,abstract,等等)。能够
明了这些修饰符单独和组合起来的含义,并且知道被修饰符修饰的任意对象在各种包相关联系下的影响。
第二部分:流程控制,断言和异常处理
能够正确使用if,switch语句并且在这些语句中能正确使用合法的参数类型。
能够正确使用所有带标签或不带标签的循环语句,能使用break,continue,能计算在循环中或循环后循环计数器的值。
能够正确使用异常和异常处理语句(try,catch,finally)。能正确声明掷出例外的方法,并知道怎样覆盖它。
知道在程序段的特定点出现的异常对程序的影响。即:异常可能是一个runtime exception,一个checked exception也可能是一个error。(这
个程序段可能包括try,catch,finally并以任何可能的合法组合出现。)。
能正确应用断言,区分正确使用的断言和不正确的。
明白关于断言机制的正确说法。
第三部分:垃圾收集
明白垃圾收集机制确定性的行为。
能用程序显式的使一个对象能被垃圾收集器合法的收集。
知道在程序的哪一点垃圾收集器能合法地收集一个对象。
第四部分:语言基础
能正确构建包声明,import声明,类声明(包括内部类),接口声明,方法声明(包括用于开始一个类的执行的main方法),变量声明及其其
它的一些说明符。
能够正确使用一些类,这些类要么实现了java.lang.Runnable这个接口,要么能正确实现在问题中构建的一些接口。
知道传入main函数的命令行参数的index value。
知道所有JAVA的keyword。注意:考试中不会出现要你区分keyword和各种常数这类深奥的问题。
明白如果没有显式地赋值的各种变量或者数组被使用会出现什么结果。
知道所有原始数据类型的取值范围,怎样声明一个String的字面值等等。
第五部分:操作与赋值
能知道当任何操作符(包括赋值操作符和intanceof操作符)应用于任何操作数(任何类型的类或访问能力或两者的任意组合)的结果。
知道String,Boolean和Object类使用equals(Object)方法后的结果。
知道当对已经知道值的变量进行&,|,&&,||操作时,哪些操作数被运算了,表达式最终的结果是怎样的。
知道Object和原始类型数据传入方法的不同方式,知道如何在这些方法中如何进行赋值或其它修改操作。
第六部分:覆盖,重载,运行时期类型及其面向对象
知道面向对象设计中封装的好处并能用程序实现紧密封装的类,能知道is a和has a的意义。
能正确使用覆盖和重载的方法,能正确调用父类或覆盖了的构建器,知道调用这些方法后的结果。
能实例化任何具体的一般顶层类和内部类。
第七部分:线程
能用java.lang,Thread和java.lang.Runnable两种方法定义,实例化和开始一个新的线程。
知道哪些情况下可能阻止一个线程的执行。
能使用synchronized,wait,notify和notifyAll去解决避免同时访问及其线程间相互通讯的问题。
当执行synchronized,wait,notify和notifyAll时,知道线程和对象锁之间的交互作用。
第八部分:在java.lang包中的基础类
能够应用Math类中的abs,ceil,floor,max,min,random,round,sin,cos,tan,sqrt方法。
正确描述String类不可改变的意义。
当执行一段程序,中间包含有wrapper类的一个实例,知道它运行的前提条件运行结果。能用下面wrapper类(例如Integer,Double,等等)的方
法来写程序:
doublevalue
floatvalue
intvalue
longvalue
parseXxx
getXxx
toString
toHexString
第九部分:集合类框架
知道如何在特定的条件下选择适合的集合类/接口。
区分正确和不正确对hashcode方法的实现。
Jason
2005-09-25 22:48:47
阅读:2473
评论:0
引用:0
来源:http://www.chinaitlab.com/www/news/article_show.asp?id=31359
SCJP 1.4 考试是 Sun Microsystems 推出的系列 Java 认证考试中的第一个,对于众多程序员来说,它是成为优秀 Java 开发人员的第一步。
该考试测试 Java 的基础知识并需要对该语言的语法和语义有深入理解。
1.参加培训或自学Java经典课程。如果有C语言和面向对象的基础,只需自学SL275课程以及JDK1.4API,否则应该参加相应的培训班进行学习。我对C语言和面向对象都有一些基础,同时又参加了SL275+Weblogic+JSP课程的学习。
2.确定考试版本,明确考查的知识点及知识点的考查难度。目前SCJP考试有两个版本1.2和1.4,两个版本的比较如下表:
其中选择题有两种形式:(1)给出一段代码让选择其运行结果;(2)给出关于某基本概念的一些描述语句让选择正确的答案。填空题一般是给出一段正确的代码,不提供选择项,而让你填写上运行结果。
两个版本考查的知识点最大的差别在于310-025包含I/O、AWT,且对各个知识点的考查难度相对较容易,而310-035中去掉了I/O和AWT部分的内容,但增加了对Assertion的考查,同时对Wrapper classes、Collections、hashcode( )和equals( )考查的难度有所加大。所以要根据自己的情况选择合适的版本。我在复习时觉得I/O这一部分的内容较多且不好记忆,就选择了310-035,这个版本较难,也是对自己的一个挑战。
3.根据考查的知识点做练习题。由于认证考试是以试题的形式来考查对知识点的掌握情况,所以多做题是通过考试的最有效方法之一,通过对SL275课程系统的学习,掌握了有关知识点的基础知识以后,必须通过做题来测试自己对知识点的掌握情况,书中写的有关知识点的内容比较概括,有时自己觉得已经掌握了这部分内容,但做题时可能会出现各式各样的错误,比如在声明main( )方法时应为public static void main( String args[ ] ){……},如果在声明时漏写了static,则在编译时可以通过,而运行时会提示出错信息;如果main( )中的参数写string args[ ],则在编译时会提示出错,在考试时有类似的题目,故意设一些陷阱,一不小心看似简单的问题却有可能失分。对于给出一段程序代码要求选择其运行结果的题目,最好亲手调试并分析其结果。
对考查Wrapper classes、Collections、hashcode( )和equals( )方法的题目要认真查看API文档(Sun官方网站提供了下载的链接,也可以在Sun网站上在线查看)并做好笔记供以后查阅。通过做题巩固知识点、适应考试题型、找出容易出错的地方,同时对所学知识点也起到了查漏补缺的作用。
4.下载相应的模拟环境进行实战训练,或者在线测试。知识点和题型都掌握以后,还不要急于考试,应该从网上下载一个模拟考试环境的软件进行实战演练。我下载了Jcertify5.0,它需在JDK1.3环境下安装运行,该软件可以设置考查的范围进行practice或者test,是一个很不错的模拟软件,里面的题目与实际考试题目难易程度相当。
通过该软件可以检验你在规定的时间内(120分钟)完成题目的情况及各个知识点掌握的程度,这样就可以根据测验结果有针对性的复习掌握的不太好的知识点,反复测验、练习,直到自己满意为止。
5.考前给自己足够的信心。通过做练习和模拟软件测验,对各个知识点都比较有把握以后,其实这时参加考试已经没有问题了,要相信自己的实力,给自己加油,此时切不可再做较难的题目,我当时就犯了这样的大忌,听说310-035的考试比较难,目前通过的人数不多,我怕考试时的题目比我做的练习题难,在考试的前一天,又做了一套题目,共43题,通过率为仅为42%,这个结果令我很失望,也丧失了自信心,晚上做梦一直考试且考试结果很糟糕,第二天醒来头昏脑胀,本来预约好的考试不得不往后推迟,这是沉痛的教训。
6.预约、考试。知名的IT认证厂商在一些大城市都有指定的考试中心,Sun认证也不例外,考试前三天到Sun指定的考试中心报名,由他们帮你注册,除了考试做题,其他的事情你尽管交给考试中心去做就行了。
7.考试注意事项。按预约的时间提前到达考试中??设置有监视器,你的一举一动都会被录制下来,所以考试来不得半点虚假,尽早打消“打小抄”的念头。考务人员帮你进入考试系统后,开始进行考试,考试分三个阶段:
(1)正式考试前的问卷调查,给定时间为15分,有10来个问题,给出四个选项供你选择,主要调查你对SCJP要考查的知识点的掌握情况,如对数组、类的定义是精通、是了解但需要别人帮助还是不懂等,这部分内容的回答不影响你的考试成绩,如果你读懂问题的意思了,你可以根据自己的实际情况进行选择,否则你尽管随意选一个,一路Next下去,直到所有的问题做完;
(2)正式考试,共120分钟,选择题在题面中注明了正确答案的数目(如:choose two),按Next做下一题,单击exhibit按钮查看题目提供的代码;
(3)题目做完后的问卷调查,同样也不影响你的考试结果。问卷结束后紧张、激动的时刻就要到了,此时你可以查看考试结果,考试系统列出你对各个知识点答题情况的一览表,如果你的成绩超过指定的分数底线,则Result即为Pass。
拿到考试结果通知单的一刻是令人兴奋的,考后的总体感觉是SCJP认证并不像自己想象的那么难,只要你做好了充分的准备,拿到SCJP认证证书不成问题。
SCJP 1.4 考试是 Sun Microsystems 推出的系列 Java 认证考试中的第一个,对于众多程序员来说,它是成为优秀 Java 开发人员的第一步。
该考试测试 Java 的基础知识并需要对该语言的语法和语义有深入理解。
1.参加培训或自学Java经典课程。如果有C语言和面向对象的基础,只需自学SL275课程以及JDK1.4API,否则应该参加相应的培训班进行学习。我对C语言和面向对象都有一些基础,同时又参加了SL275+Weblogic+JSP课程的学习。
2.确定考试版本,明确考查的知识点及知识点的考查难度。目前SCJP考试有两个版本1.2和1.4,两个版本的比较如下表:
其中选择题有两种形式:(1)给出一段代码让选择其运行结果;(2)给出关于某基本概念的一些描述语句让选择正确的答案。填空题一般是给出一段正确的代码,不提供选择项,而让你填写上运行结果。
两个版本考查的知识点最大的差别在于310-025包含I/O、AWT,且对各个知识点的考查难度相对较容易,而310-035中去掉了I/O和AWT部分的内容,但增加了对Assertion的考查,同时对Wrapper classes、Collections、hashcode( )和equals( )考查的难度有所加大。所以要根据自己的情况选择合适的版本。我在复习时觉得I/O这一部分的内容较多且不好记忆,就选择了310-035,这个版本较难,也是对自己的一个挑战。
3.根据考查的知识点做练习题。由于认证考试是以试题的形式来考查对知识点的掌握情况,所以多做题是通过考试的最有效方法之一,通过对SL275课程系统的学习,掌握了有关知识点的基础知识以后,必须通过做题来测试自己对知识点的掌握情况,书中写的有关知识点的内容比较概括,有时自己觉得已经掌握了这部分内容,但做题时可能会出现各式各样的错误,比如在声明main( )方法时应为public static void main( String args[ ] ){……},如果在声明时漏写了static,则在编译时可以通过,而运行时会提示出错信息;如果main( )中的参数写string args[ ],则在编译时会提示出错,在考试时有类似的题目,故意设一些陷阱,一不小心看似简单的问题却有可能失分。对于给出一段程序代码要求选择其运行结果的题目,最好亲手调试并分析其结果。
对考查Wrapper classes、Collections、hashcode( )和equals( )方法的题目要认真查看API文档(Sun官方网站提供了下载的链接,也可以在Sun网站上在线查看)并做好笔记供以后查阅。通过做题巩固知识点、适应考试题型、找出容易出错的地方,同时对所学知识点也起到了查漏补缺的作用。
4.下载相应的模拟环境进行实战训练,或者在线测试。知识点和题型都掌握以后,还不要急于考试,应该从网上下载一个模拟考试环境的软件进行实战演练。我下载了Jcertify5.0,它需在JDK1.3环境下安装运行,该软件可以设置考查的范围进行practice或者test,是一个很不错的模拟软件,里面的题目与实际考试题目难易程度相当。
通过该软件可以检验你在规定的时间内(120分钟)完成题目的情况及各个知识点掌握的程度,这样就可以根据测验结果有针对性的复习掌握的不太好的知识点,反复测验、练习,直到自己满意为止。
5.考前给自己足够的信心。通过做练习和模拟软件测验,对各个知识点都比较有把握以后,其实这时参加考试已经没有问题了,要相信自己的实力,给自己加油,此时切不可再做较难的题目,我当时就犯了这样的大忌,听说310-035的考试比较难,目前通过的人数不多,我怕考试时的题目比我做的练习题难,在考试的前一天,又做了一套题目,共43题,通过率为仅为42%,这个结果令我很失望,也丧失了自信心,晚上做梦一直考试且考试结果很糟糕,第二天醒来头昏脑胀,本来预约好的考试不得不往后推迟,这是沉痛的教训。
6.预约、考试。知名的IT认证厂商在一些大城市都有指定的考试中心,Sun认证也不例外,考试前三天到Sun指定的考试中心报名,由他们帮你注册,除了考试做题,其他的事情你尽管交给考试中心去做就行了。
7.考试注意事项。按预约的时间提前到达考试中??设置有监视器,你的一举一动都会被录制下来,所以考试来不得半点虚假,尽早打消“打小抄”的念头。考务人员帮你进入考试系统后,开始进行考试,考试分三个阶段:
(1)正式考试前的问卷调查,给定时间为15分,有10来个问题,给出四个选项供你选择,主要调查你对SCJP要考查的知识点的掌握情况,如对数组、类的定义是精通、是了解但需要别人帮助还是不懂等,这部分内容的回答不影响你的考试成绩,如果你读懂问题的意思了,你可以根据自己的实际情况进行选择,否则你尽管随意选一个,一路Next下去,直到所有的问题做完;
(2)正式考试,共120分钟,选择题在题面中注明了正确答案的数目(如:choose two),按Next做下一题,单击exhibit按钮查看题目提供的代码;
(3)题目做完后的问卷调查,同样也不影响你的考试结果。问卷结束后紧张、激动的时刻就要到了,此时你可以查看考试结果,考试系统列出你对各个知识点答题情况的一览表,如果你的成绩超过指定的分数底线,则Result即为Pass。
拿到考试结果通知单的一刻是令人兴奋的,考后的总体感觉是SCJP认证并不像自己想象的那么难,只要你做好了充分的准备,拿到SCJP认证证书不成问题。
Jason
2005-09-25 22:44:28
阅读:296
评论:0
引用:0
最近有一目标,就是考sun公司的scjp认证,在此收集一点资料,作考试的粮草!
Jason
2005-09-25 22:31:59
阅读:2800
评论:2
引用:0
