Practical Java 学习笔记-- 1 一般技术(General Techniques)

Practical Java 学习笔记-- 1 一般技术(General Techniques)
实践1:参数以by value方式而非by reference方式传递
实践2:对不变的data和object reference使用final
实践3:缺省情况下所有non-static函数都可被重写
实践4:在array和Vectors之间慎重选择
实践5:多态(polymorphism)优于instanceof
实践6:必要时才使用instanceof
实践7:一旦不需要object reference,就将它设为null

实践1:参数以by value方式而非by reference方式传递

import  java.awt.Point;

class  PassByValue {
    
public   static   void  modifyPoint(Point pt,  int  j) {
        pt.setLocation(
5 5 );  //  1
        j  =   15 ;
        System.out.println(
" During modifyPoint  "   +   " pt =  "   +  pt  +   "  and j =  "   +  j);
    }

    
public   static   void  main(String args[]) {
        Point p 
=   new  Point( 0 0 );  //  2
         int  i  =   10 ;
        System.out.println(
" Before modifyPoint  "   +   " p  =  "   +  p  +   "  and i =  "   +  i);
        modifyPoint(p, i); 
//  3
        System.out.println( " After  modifyPoint  "   +   " p  =  "   +  p  +   "  and i =  "   +  i);
    }
}
这段代码在//2处建立了一个Point对象并设初值为(0,0),接着将其值赋予object reference 变量p。然后对基本类型int i赋值10。//3调用static modifyPoint(),传入p和i。modifyPoint()对第一个参数pt调用了setLocation(),将其左边改为(5,5)。然后将第二个参数j赋值为15.当modifyPoint()返回的时候,main()打印出p和i的值。

程序输出如下:
Before modifyPoint p   =  java.awt.Point [ x=0,y=0 ]   and  i  =   10
During modifyPoint pt 
=  java.awt.Point [ x=5,y=5 ]   and  j  =   15
After   modifyPoint p  
=  java.awt.Point [ x=5,y=5 ]   and  i  =   10

这显示modifyPoint()改变了//2 所建立的Point对象,却没有改变int i。在main()之中,i被赋值10.由于参数通过by value方式传递,所以modifyPoint()收到i的一个副本,然后它将这个副本改为15并返回。main()内的原值i并没有受到影响。

对比之下,事实上modifyPoint() 是在与“Point 对象的 reference 的复件”打交道,而不是与“Point对象的复件”打交道。当p从main()被传入modifyPoint()时,传递的是p(也就是一个reference)的复件。所以modifyPoint()是在与同一个对象打交道,只不过通过别名pt罢了。在进入modifyPoint()之后和执行 //1 之前,这个对象看起来是这样:

所以//1 执行以后,这个Point对象已经改变为(5,5)。

实践2:对不变的data和object reference使用final

Java 关键字 final 用来表示常量数据。例如:

public   class  Test {
    
static   final   int  someInt  =   10 ;
    
//  
}

这段代码声明了一个 static 类变量,命名为 someInt,并设其初值为10。
任何试图修改 someInt 的代码都将无法通过编译。例如:

     //  
    someInt  =   9 //  Error
    
//  

关键字 final 可防止 classes 内的 instance 数据遭到无意间的修改。如果我们想要一个常量对象,又该如何呢?例如:

class  Circle {
    
private   double  rad;

    
public  Circle( double  r) {
        rad 
=  r;
    }

    
public   void  setRadius( double  r) {
        rad 
=  r;
    }

    
public   double  radius() {
        
return  rad;
    }
}

public   class  FinalTest {
    
private   static   final  Circle wheel  =   new  Circle( 5.0 );

    
public   static   void  main(String args[]) {
        System.out.println(
" Radius of wheel is  "   +  wheel.radius());
        wheel.setRadius(
7.4 );
        System.out.println(
" Radius of wheel is now  "   +  wheel.radius());
    }
}

这段代码的输出是:

Radius of wheel is  5.0
Radius of wheel is now 
7.4

在上述第一个示例中,我们企图改变final 数据值时,编译器会侦测出错误。
在第二个示例中,虽然代码改变了 instance变量wheel的值,编译器还是让它通过了。我们已经明确声明wheel为final,它怎么还能被改变呢?
不,我们确实没有改变 wheel 的值,我们改变的是wheel 所指对象的值。wheel 并无变化,仍然指向(代表)同一个对象。变量wheel是一个 object reference,它指向对象所在的heap位置。有鉴如此,下面的代码会怎样?

public   class  FinalTest {
    
private   static   final  Circle wheel  =   new  Circle( 5.0 );

    
public   static   void  main(String args[]) {
        System.out.println(
" Radius of wheel is  "   +  wheel.radius());
        wheel 
=   new  Circle( 7.4 ); // 1
        System.out.println(
" Radius of wheel is now  "   +  wheel.radius());
    }
}

编译代码,// 1 处出错。由于我们企图改变 final 型变量 wheel 的值,所以这个示例将产生编译错误。换言之,代码企图令wheel指向其他对象。变量wheel是final,因此也是不可变的。它必须永远指向同一个对象。然而wheel所指向的对象并不受关键字final的影响,因此是可变的。

关键字 final 只能防止变量值的改变。如果被声明为 final 的变量是个 object reference,那么该reference不能被改变,必须永远指向同一个对象,但被指的那个对象可以随意改变内部的属性值。

实践3:缺省情况下所有non-static函数都可以被覆盖重写

关键字final 在Java中有多重用途,即可被用于instance变量、static变量,也可用于classes或methods,用于类,表示该类不能有子类;用于方法,表示该方法不允许被子类覆盖。

实践4:在array和vectors之间慎重选择

array和Vector的比较

 

支持基本类型

支持对象

自动改变大小

速度快

array

Yes

Yes

No

Yes

Vector

No(1.5以上支持)

Yes

Yes

No

实践5:多态(polymorphism)优于instanceof

代码1:instanceof方式

interface  Employee {
    
public   int  salary();
}

class  Manager  implements  Employee {
    
private   static   final   int  mgrSal  =   40000 ;

    
public   int  salary() {
        
return  mgrSal;
    }
}

class  Programmer  implements  Employee {
    
private   static   final   int  prgSal  =   50000 ;
    
private   static   final   int  prgBonus  =   10000 ;

    
public   int  salary() {
        
return  prgSal;
    }

    
public   int  bonus() {
        
return  prgBonus;
    }
}

class  Payroll {
    
public   int  calcPayroll(Employee emp) {
        
int  money  =  emp.salary();
        
if  (emp  instanceof  Programmer)
            money 
+=  ((Programmer) emp).bonus();  //  Calculate the bonus
         return  money;
    }

    
public   static   void  main(String args[]) {
        Payroll pr 
=   new  Payroll();
        Programmer prg 
=   new  Programmer();
        Manager mgr 
=   new  Manager();
        System.out.println(
" Payroll for Programmer is  "   +  pr.calcPayroll(prg));
        System.out.println(
" payroll for Manager is  "   +  pr.calcPayroll(mgr));
    }
}
依据这个设计,calcPayroll()必须使用instanceof操作符才能计算出正确结果。因为它使用了Employee接口,所以它必须断定Employee对象究竟实际属于哪个class。程序员有奖金而经理没有,所以你必须确定Employee对象的运行时类型。

代码2:多态方式
interface  Employee {
    
public   int  salary();

    
public   int  bonus();
}

class  Manager  implements  Employee {
    
private   static   final   int  mgrSal  =   40000 ;
    
private   static   final   int  mgrBonus  =   0 ;

    
public   int  salary() {
        
return  mgrSal;
    }

    
public   int  bonus() {
        
return  mgrBonus;
    }
}

class  Programmer  implements  Employee {
    
private   static   final   int  prgSal  =   50000 ;
    
private   static   final   int  prgBonus  =   10000 ;

    
public   int  salary() {
        
return  prgSal;
    }

    
public   int  bonus() {
        
return  prgBonus;
    }
}

class  Payroll {
    
public   int  calcPayroll(Employee emp) {
        
//  Calculate the bonus. No instanceof check needed.
         return  emp.salary()  +  emp.bonus();
    }

    
public   static   void  main(String args[]) {
        Payroll pr 
=   new  Payroll();
        Programmer prg 
=   new  Programmer();
        Manager mgr 
=   new  Manager();
        System.out.println(
" Payroll for Programmer is  "   +  pr.calcPayroll(prg));
        System.out.println(
" Payroll for Manager is  "   +  pr.calcPayroll(mgr));
    }
}
在这个设计中,我们为Employee接口增加了 bonus(),从而消除了instanceof的必要性。实现Employee接口的两个 classes:Programmer和Manager,都必须实现salary()和bonus()。这些修改显著简化了calcPayroll()。


实践6:必要时才使用instanceof

import  java.util.Vector;

class  Shape {
}

class  Circle  extends  Shape {
    
public   double  radius() {
        
return   5.7 ;
    }
    
//  
}

class  Triangle  extends  Shape {
    
public   boolean  isRightTriangle() {
        
//  Code to determine if triangle is right
         return   true ;
    }
    
//  
}

class  StoreShapes {
    
public   static   void  main(String args[]) {
        Vector shapeVector 
=   new  Vector( 10 );
        shapeVector.add(
new  Triangle());
        shapeVector.add(
new  Triangle());
        shapeVector.add(
new  Circle());
        
//  
        
//  Assume many Triangles and Circles are added and removed
        
//  
         int  size  =  shapeVector.size();
        
for  ( int  i  =   0 ; i  <  size; i ++ ) {
            Object o 
=  shapeVector.get(i);
            
if  (o  instanceof  Triangle) {
                
if  (((Triangle) o).isRightTriangle()) {
                    
//  
                }
            } 
else   if  (o  instanceof  Circle) {
                
double  rad  =  ((Circle) o).radius();
                
//  
            }
        }
    }
}
这段代码表明在 这种场合下 instanceof 操作符是必需的。当程序从Vector 取回对象,它们属于java.lang.Object。利用instanceof确定对象实际属于哪个class后,我们才能正确执行向下转型,而不至于在运行期抛出异常。

实践7:一旦不再需要object reference,就将它设为null

你可能感兴趣的:(Practical Java 学习笔记-- 1 一般技术(General Techniques))