scjp总结三四

Section 3 Garbage Collection
Objective 1,2 & 3
State the behaviour that is guaranteed by the garbage collection systemWrite code that explicitly 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
    
数据直接值:
整数直接数值:int   小数点直接数值: double 指数直接数值:double
 
数据类型转型(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 使用运算符
操作符的分类
1.          算术操作符 (+ , - , * , / , %,++,--)
2.          一元操作符  (++, --, - , +)
3.          关系和条件操作符 关系操作符(>,>=,<,<=,==,!=) 条件操作符(&&,||,!,&,|,^)
4.          移位操作符(<<,>>,>>>) 位操作符(&,|,^,~)
5.          赋值操作符(=)
6.          其它操作符(?:,[],.,new,instanceof,(类型))
注:除了=,==,!=运算符外,其它运算符只能用于基本类型。String类支持+,+=操作符
例: String aStr=2+”hello”;
instanceof操作符用来检验某特殊对象是不是某类或该类的子类的实例,还可以检验某对象的类或子类是否实现了某接口。注意,数组也是对象,instanceof同样适合与数组。
 
赋值操作符=
1.     基本数据类型的赋值操作
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
2.     引用数据类型的赋值操作
引用数据类型的赋值,例如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.
奇怪的==(对于引用类型==比较两个对象的内存地址,这可不是我们想要的)
double d=12.0;
int i=12;
Integer i2=new Interger(12);
Double d2=new Double(12);
Integer i3=new Interger(12);
d==i ; true
i2==i3; false
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方法:
  当且仅当equals方法的参数不为空并且Boolean对象所包含的boolean值相同时,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();
 }
}
分析上面程序的初始化过程:
1.          程序的入口在Beetle.main()方法。程序执行时,类装载器被启动,找到Beetle.class并装载,由于Beetle类是Insect类的子类所以类装载器也将Insect.class装载。如果基类还要基类,这个过程将继续。
2.          类加载完成后,将进行静态初始化过程,首先从根基类(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");
3.          静态初始化完成后,将进行类实例的生成。首先,对象内的所有基本类型都会被评为设予缺省值,对象引用则被设予null.然后,基类的构造函数被唤起,缺省条件下基类的缺省构造函数被自动唤起,但你可用super(第一个运作)来调用基类的其它构造函数。执行Insect类的缺省函数。
4.          基类构造完成后,是实例变量按次序被初始化,最后,才执行构造本体的剩余部分。
 
final类, 方法,变量
final变量是固定不变的数据。它可以:
1.          可以是永不改变的编译期常量(compile-time constant)
2.          可以是执行期(runtime)被初始化,而你不想再改变它。
final的对象引用的意义是它让引用保持不变而不是对象本身。某个引用一旦被初始化后,便再也不能指向另一个对象,但此对象本身的内容是可以改变的。
Java允许产生所谓的”blank finals”,也就是允许我们将数据成员声明为final,却不给予初值。注意:在任何情况下,blank finals必须在使用之间进行初始化, 而且编译器保证此事。所以,final的赋值运行如果不是发生在其定义处,就得在构造函数中以表达式设定其值。
final参数
 final参数意指你无法在方法中令该引用指向它处。
final方法
 final方法的原因: 第一:锁住这个函数,使子类不能改意其意义,即无法覆写;第二:效率。
 类中的所有prviate函数自然而然会是final. private函数可以在子类中隐藏,final函数却不能。
final类
final类就是说此类不能被继承。final类中的所有方法是final的但数据成员可是fianl也可不是fianl.
示例:final的使用
mport java.util.*;
 
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[i]++; // 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类
Thread类中最重要的是run方法,我们在创建的 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)
1.             线程进入睡眠状态,那么必须经过指定的时间后线程返回可运行状态
2.             线程由于调用wait而处于暂停状态,另一个对象调用了notfiy或notifyAll通知等待线程
3.             线程由于IO操作而阻塞,IO完成后线程返回可运行状态
4.             线程由于调用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[i] = new SelfishRunner(i);
            runners[i].setPriority(2);
        }
        for (int i = 0; i < NUMRUNNERS; i++)
            runners[i].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));
            } catch (InterruptedException e) { }
        }
    }
}
消费者
public class Consumer extends Thread {
    private CubbyHole cubbyhole;
    private int number;
 
    public Consumer(CubbyHole c, int number) {
        cubbyhole = c;
        this.number = number;
    }
 
    public void run() {
        int value = 0;
        for (int i = 0; i < 10; i++) {
            value = cubbyhole.get();
            System.out.println("Consumer #" + this.number
                               + " got: " + value);
        }
    }
}
测试
public class ProducerConsumerTest {
    public static void main(String[] args) {
        CubbyHole c = new CubbyHole();
        Producer p1 = new Producer(c, 1);
        Consumer c1 = new Consumer(c, 1);
 
        p1.start();
        c1.start();
    }
}
 
高级话题
如果线程正拥有一个锁(因为它在一个同步方法或代码块中),则当它调用 yield() 时不能够释放这个锁。这就意味着即使这个线程已经被挂起,等待这个锁释放的其他线程依然不能继续运行。为了缓解这个问题,最好不在同步方法中调用 yield 方法。将那些需要同步的代码包在一个同步块中,里面不含有非同步的方法,并且在这些同步代码块之外才调用 yield。
 
细粒度锁
在对象级使用锁通常是一种比较粗糙的方法,如果一个对象拥有多个资源,就不需要只为让一个线程使用其中一部分资源,就将所有的线程锁在外面。由于每个对象都有锁,可以利用虚拟对象来实现细粒度锁。
class FineGrainLock {
 
   MyMemberClass x, y;
   Object xlock = new Object(), ylock = new Object();
 
   public void foo() {
      synchronized(xlock) {
         //access x here
      }
 
      //do something here - but don't use shared resources
 
      synchronized(ylock) {
         //access y here
      }
   }
 
   public void bar() {
      synchronized(this) {
         //access both x and y here
      }
      //do something here - but don't use shared resources
   }
}
 
信号量实现
信号量计数 (counting semaphore)将一组可获得资源的管理封装起来。信号量是在简单上锁的基础上实现的,相当于能令线程安全执行,并初始化为可用资源个数的计数器。例如我们可以将一个信号量初始化为可获得的数据库连接个数。一旦某个线程获得了信号量,可获得的数据库连接数减一。线程消耗完资源并释放该资源时,计数器就会加一。当信号量控制的所有资源都已被占用时,若有线程试图访问此信号量,则会进入阻塞状态,直到有可用资源被释放。
class Semaphore {
   private int count;
   public Semaphore(int n) {
      this.count = n;
   }
 
   public synchronized void acquire() {
      while(count == 0) {
         try {
            wait();
         } catch (InterruptedException e) {
            //keep trying
         }
      }
      count--;
   }
   
   public synchronized void release() {
      count++;
      notify(); //alert a thread that's blocking on this semaphore
   }
}
 
Volatile 变量. volatile 关键字是 Java 语言为优化编译器设计的。以下面的代码为例:
class VolatileTest {
 
   public void foo() {
      boolean flag = false;
 
      if(flag) {
         //this could happen
      }
   }
}
 
一个优化的编译器可能会判断出 if 部分的语句永远不会被执行,就根本不会编译这部分的代码。如果这个类被多线程访问, flag 被前面某个线程设置之后,在它被 if 语句测试之前,可以被其他线程重新设置。用 volatile 关键字来声明变量,就可以告诉编译器在编译的时候,不需要通过预测变量值来优化这部分的代码。
 
无法访问的线程 有时候虽然获取对象锁没有问题,线程依然有可能进入阻塞状态。在 Java 编程中 IO 就是这类问题最好的例子。当线程因为对象内的 IO 调用而阻塞时,此对象应当仍能被其他线程访问。该对象通常有责任取消这个阻塞的 IO 操作。造成阻塞调用的线程常常会令同步任务失败。如果该对象的其他方法也是同步的,当线程被阻塞时,此对象也就相当于被冷冻住了。其他的线程由于不能获得对象的锁,就不能给此对象发消息(例如,取消 IO 操作)。必须确保不在同步代码中包含那些阻塞调用,或确认在一个用同步阻塞代码的对象中存在非同步方法。尽管这种方法需要花费一些注意力来保证结果代码安全运行,但它允许在拥有对象的线程发生阻塞后,该对象仍能够响应其他线程。
 
Section 8 The java.lang package
Objective 1, methods in the Math class
Write code using the following methods of the java.lang.Math class: abs ceil floor max min random round sin cos tan sqrt
目标1 Math类方法的使用
           会用Math类的以下方法: abs, ceil,floor,max,min,random,round,sin,cos,tan,sqrt
public final class Math extends Object
Math类是final类,不能有子类。在Math类中的方法都是静态方法。Math类没在提供任何的构造器方法,因此,你不能对它进行实例化。
Static abs     Returns the absolute value of a double(int long float) value 返回参数的绝对值
Static double ceil(double a)  Returns the smallest (closest to negative infinity) double value that is not less than the argument and is equal to a mathematical integer. 返回大于或等于参数的整数值
Static double floor(double a) Returns the largest (closest to positive infinity) double value that is not greater than the argument and is equal to a mathematical integer 返回小于或等于参数的整数值
Static double random() Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0  返回大于或等于0小于1的随机数
static long round(double a)  static int round(float) Returns the closest long(int ) to the argument   返回距离参数最近的整数 
注意:
2.0 <=x < 2.5. then Math.round(x)==2.0
2.5 <=x < 3.0 the Math.round(x)==3.0 
max and min 返回两个参数的最大或最小值。
sin,cos,tan 三角函数,参数以弧度表示
static double sqrt(double a) Returns the correctly rounded positive square root of a double value.    返回参数的平方根
 
示例:
public class MyMat{
public static void main(String[] argv){
           System.out.println("Math's Ceil Function");
           System.out.println(Math.ceil(-99.1));
        System.out.println(Math.ceil(-99));
        System.out.println(Math.ceil(99));
        System.out.println(Math.ceil(-.01));
        System.out.println(Math.ceil(0.1));
        System.out.println("Math's Floor Function");
        System.out.println(Math.floor(-99.1));
        System.out.println(Math.floor(-99));
        System.out.println(Math.floor(99));
        System.out.println(Math.floor(-.01));
        System.out.println(Math.floor(0.1));
        System.out.println("Math's Max/Min Function");
        System.out.println(Math.max(-1,-10));
        System.out.println(Math.max(1,2));
        System.out.println(Math.min(1,1));
        System.out.println(Math.min(-1,-10));
        System.out.println(Math.min(1,2));
        System.out.println("Math's Round Function");
        System.out.println(Math.round(1.01));
        System.out.println(Math.round(1.5));
           System.out.println(Math.round(-2.1));
           System.out.println(Math.round(20));
        System.out.println("Math's Random Function");
        for(int i=0;i<10;i++){
                   System.out.println((int)(Math.random()*10)+1);
        }
 
        }
}
 
Objective 2, The immutability of Strings
Describe the significance of the immutability of String objects
 
目标2 字符串类的不变性
           了解字符串类的不变性的意义
 
String对象一旦创建后,就不能修改其内容。记住,不论问题如向,一旦String对象创建后,对象将无法修改,但是对象的引用可以修改以指向其它的String对象。同时,要了解有关String pool的概念。String的连接操作实际上是在萤幕的后面,新生成的一个对象 str+=”dddd”
String类的主要方法:
Concat(String str): 追加str到未尾。
indexOf(int c): 对象中第一个ch出现的索引。
Length(): 字符数
substring(int beginIndex, int endIndex),substring(int beginIndex)
valueOf(int i):  
 
StringBuffer类提供了一种可修改的字符串。它会自动增长以为增加的字符提供空间。
增加: append方法
插入: insert方法
反转: reverse方法
删除: delet方法
 
示例:
class MyString{
           public static void main(String args[]){
                      String a="hello";
                      String b="world";
                      StringBuffer buf1=new StringBuffer(a);
                      System.out.println(a.toUpperCase());
                      replace(a,buf1);
                      System.out.println(a);
                      System.out.println(buf1);
           }
           static void replace(String str,StringBuffer buf){
                      str.replace('h','j');
                      buf.reverse();
                      buf=new StringBuffer("world");
           }
}
 
Objective 3, The wrapper classes
Describe the significance of wrapper classes, including making appropriate selections in the wrapper classes to suit specified behaviour requirements, stating the result of executing a fragment of code that includes an instance of one of the wrapper classes..DoubleValue, floatValue, longValue,parseXxx,getXxx,toString,toHexString.
目标3 包装类
包裹类Integer、 String 、Float、 Double等都是final类,不能被继承!
包装类包括:
 Byte,Short,Double,Float,Integer,Long,BigInteger,BigDecimal,Boolean,Character,Void
 
public final class Integer  extends Number   implements Comparable
构造器方法:Integer(int value)   
Integer(String s)
所有的包裹类具有和String一样的不变性,其实可以将String也理解成包裹类。一旦创建后,就不能修改其中代表的值。
包装类提供了工具方法用于在数字与字符串之间相互转化。这样,如果你有代表数字的字符串时,你可用包装类来执行计算。这些工具方法都是静态。
主要的实例方法与静态工具方法:
实例方法:
XXX XXXvalue ()  将所引用对象的值以XXX返回。
XXX: double ,float, long,int, short,byte
静态方法:
public static XXX parseXXX(String s) throws NumberFormatException  返回与str格式的XXX类型的数据。
XXX: byte,int,long,float,double
 
public static XXX valueOf(String s)  throws NumberFormatException 返回与str格式的XXX类型的数据。
XXX: Byte,Integer,Float,Double
 
public static String toBinaryString(int i)
public static String toHexString(int i)
示例:
class MyWrapper{
           public static void main(String[] args){
                      Boolean b1=new Boolean(true);
                      Boolean b2=new Boolean("true");
                      Boolean b3=new Boolean("xxxx");
                      Boolean b4=new Boolean("false");
                      if(b1.equals(b2)&&b3.equals(b4)) System.out.println("Boolean equals");
                      Integer i1=Integer.valueOf("12");
                      Integer i2=new Integer("12");
                      Integer i3=new Integer(12);
                      if(i1.equals(i2)&&i2.equals(i3)) System.out.println("Integer equals");
                      System.out.println(i1.doubleValue());
                      System.out.println(i1.intValue()+i2.intValue());
                      System.out.println(Integer.toBinaryString(Integer.parseInt("3")));
           }
 
}
 
Float.ValueOf(String s)的别人的一些看法:
1. I do not think that string argument is parsed at compile time. Therefore, compiler will not give any error even if you put "aaa" as argument.
2. Any numerical argument that can be promoted to float, will be promoted.
3. If string contains a number beyond the limits of a float, + or - infinity will be printed
Float.valueOf(“aaa”): //编译OK,运行抛出NumberFormatException
Float.valueOf(“1.2d”); //OK
Float f=new Float(1.2d); //OK
Section 9 The java.util package
Objective 1, The collection classes/interfaces
Make appropriate selection of collection classes/interfaces to suit specified behavior requirements.
目标1 集合类/接口
选择合适的集合类/接口来满足你的需求
 
容器的分类图
JAVA 2容器库从整体上划分为Collection接口和Map接口
Collection: 一组各自独立的元素,通常拥有相同的套用规则:List必须以特定次序来持有各元素;Set无法拥有重复元素。
Map: 一群成对的key-value对象。
Collection的方法:
public interface Collection {
    // Basic Operations
    int size();
    boolean isEmpty();
    boolean contains(Object element);
    boolean add(Object element);    // Optional
    boolean remove(Object element); // Optional
    Iterator iterator();
 
    // Bulk Operations
    boolean containsAll(Collection c);
    boolean addAll(Collection c);    // Optional
    boolean removeAll(Collection c); // Optional
    boolean retainAll(Collection c); // Optional
    void clear();                    // Optional       
 
    // Array Operations
    Object[] toArray();
    Object[] toArray(Object a[]);
}
 
 
Set:
 Set是不包含重复元素的Collection.它拥有与Collection一模一样的接口。 SDK中包含两个通用的Set实现-HashSet和TreeSet. HashSet将它的元素存储在一个散列表中,这个是性能较好的实现。TreeSet将的元素存储在一个红黑树中,它保证迭代表的次序。注意,在set中add(Object o)时,如果set中已有这个对象时,则set保持不变并返回false。在这里不是抛出异常而是返回false.TreeSet是惟一实现了SortedSet接口的类,将保证其中元素处于排序状态。
 
List:
 List是一个有序的Collection,它有时称为序列(sequence)。列表可能包含重复的元素。List除了从Collection继承的方法外,还包含:
位置操作,搜索,列表迭代,范围视图
public interface List extends Collection {
    // Positional Access
    Object get(int index);
    Object set(int index, Object element);            // Optional
    void add(int index, Object element);              // Optional
    Object remove(int index);                         // Optional
    abstract boolean addAll(int index, Collection c); // Optional
 
    // Search
    int indexOf(Object o);
    int lastIndexOf(Object o);
 
    // Iteration
    ListIterator listIterator();
    ListIterator listIterator(int index);
 
    // Range-view
    List subList(int from, int to);
}
JAVA 2 SDK中有两个通用的List实现:ArrayList 和 LinkedList。 ArrayList一般是性能较好的实现,而LinkedList在某此环境下具有较好的性能。另外,Vector已经为实现List而改进。
 
Map接口
 Map是一个将键映射到值的对象。映射不能包含重复的键。
public interface Map {
    // Basic Operations
    Object put(Object key, Object value);
    Object get(Object key);
    Object remove(Object key);
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    int size();
    boolean isEmpty();
 
    // Bulk Operations
    void putAll(Map t);
    void clear();
 
    // Collection Views
    public Set keySet();
    public Collection values();
    public Set entrySet();
 
    // Interface for entrySet elements
    public interface Entry {
        Object getKey();
        Object getValue();
        Object setValue(Object value);
    }
}
SDK 包含两个新的通用MAP实现: HashMap和TreeMap。 HashMap在散列表中存储它的项目,这是性能较好的实现。TreeMap将它的项目存储在一个红黑树中,它保证迭代的次序。
 
遗留类
Vector类:
Hashtable类:
Stack类:
BitSet类:
 
Objective 2, implementing hashCode
Distinguish between correct and incorrect implementations of hashcode methods.
 
Object中的hashCode方法
public int hashCode()
Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable.
The general contract of hashCode is:
 
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
由于JAVA中的所有类都继承了Object类,所以每个类都有hashCode方法,如果你不重写此方法则它返回对象的内存地址。在以散列表为基础的集合类将使用hashcode值。下面引用了jdk1.4对hashcode的要求。
“Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.”
它说,倘若equals方法没有修改,则在程序运行中,多次调用同一个对象的hashCode方法时要返回相同的值。但不要求每次程序运行时,对象返回恒定的值。在这里,你可能发现equals方法与hashCode方法之间有某种关系。
 
equals方法与hashCode方法
           equals方法也是Object类的方法,因此所有的java类都继承了这个方法。缺省条件下它通过内存地址来判定对象是否相等。一般来说,你需要重写equals方法以满足你的要求。在
 
Collections 与 Arrays 类
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值