从制造到创造
软件工程师成长之路
posts - 292,  comments - 96,  trackbacks - 0
实践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(
55); // 1
        j = 15;
        System.out.println(
"During modifyPoint " + "pt = " + pt + " and j = " + j);
    }

    
public static void main(String args[]) {
        Point p 
= new Point(00); // 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

posted on 2008-02-26 17:56 CoderDream 阅读(296) 评论(0)  编辑  收藏 所属分类: 学习笔记

只有注册用户登录后才能发表评论。


网站导航:
 

<2008年2月>
272829303112
3456789
10111213141516
17181920212223
2425262728291
2345678

常用链接

留言簿(9)

我参与的团队

随笔分类(245)

随笔档案(239)

文章分类(3)

文章档案(3)

收藏夹(576)

友情链接

搜索

  •  

积分与排名

  • 积分 - 456226
  • 排名 - 114

最新评论

阅读排行榜

评论排行榜