一个普通存在的误解是:java中的参数是以by value方式传递。其实不是这样的,参数是以by value方式传递的。请看示例:
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);
}
}
这显示,modifyPoint()改变了//2所建立的Point对象,却没有改变int i。在main()之中,i被赋值为10。由于参数通过by value方式传递,所以modifyPoint()收到i的一个副本,然后它将这个副本必为15并返回。main()内的原值i并没有受到影响。
对于Point对象,其实modifyPoint()是与“Point对象的reference p的复件”打交道,而不是与“Point对象的复件”打交道。记住,p是个object reference,并且Java以by value方式传递参数,或者更准确点说,Java以by value方式传递object reference。当p从main()被传入modifyPoint()时,传递的是p(也就是一个reference)的复件。所以modifyPoint()是在与同一个对象打交道,只不过通过别名pt罢了。在进入modifyPoint()之后和执行//1之前,内存中应该是这样的:
如果你并不想modifyPoint()改变传进的Point对象,你可以传递一个克隆对象(见64、66)或者将Point设计成不可变的(见65)。
实践2、 对不变的data和object references使用finalclassFinalTest {
staticfinalintsomeInt= 10;
staticfinalStringBufferobjRef=newStringBuffer("sring");
staticvoidprt() {
System.out.println("someInt="+someInt+" - objRef="+objRef);
}
publicstaticvoidmain(String[] args) {
prt();
//不能重新分配FinalTest.someInt
//!!someInt = 20;//1
objRef.append(" other");//2
//不能重新分配FinalTest.objRef
//!!objRef = new StringBuffer(); //3
prt();
}
}
输出:
someInt=10 - objRef=sring
someInt=10 - objRef=sring other
程序里的//1处理我们应该很清楚了,但//2处又是为什么呢?我们不是已经声明objRef声明成final,为什么还能改变?不,我们确实没有改变objRef的值,我们改变的是objRef所指对象的值,objRef并无变化,仍然指向同一个对象。变量objRef是一个object reference,它指向对象所在的heap位置。而//3处正是我们想的那样,编译出错了,因为你试图改objRef的值,换而言之,它企图令objRe指向其他物体。然而objRef所指对象并不受关键词final的影响,因此所指向的对象本身是可变的。
关键词final只能防止变量值的改变。如果被声明为final的变量是个object reference,那么该reference不能被改变,必须永远指向同一个对象,然而被指向的那个对象是可以随意改变的。
实践3、 缺省情况下所有non-private、non-static函数都可以被覆写缺省情况下,类中任何non-private、non-static函数都允许被子类覆写。类的设计者如果希望阻止子类覆写(修改)某个函数,则必须采取明确的动作,也就是将该函数声明为final。
关键字final在Java中有多重用途,即可被用于变量(不能修改),也可用于类(不能继承)与方法(不能覆写)。
声明某个类为final,也就暗暗声明了这个类的所有函数都为final。这种做法可以阻止它派生类,从而禁止任何人覆写此类的所有函数。如果这种设计对你而言过于严苛,也可以考虑只将某些方法声明成final,这种方式允许你派生出类,但不允许你覆写你声明成final的方法。另外,final比non-final方法的性能要高。
实践4、 在arrays和ArrayList之间慎重选择在新建一个数组时,每个元素都将依据其自己类型而被赋予缺省值:boolean-false,char- '/u0000',byte、short、int、long-0,float、double-0.0,object reference-null。
数组的容量是固定的,一旦指定了就不可更改,但ArrayList的容量是可变的,它会随着元素的增加自动的增长。数组即可存放基本类型也可存储引用类型,而ArrayList只能存放引用类型元素(虽然1.5可以,但这是借助于自动装箱特性实现的)。
数组比ArrayList拥有更高的性能。
实践5、 多态(polymorphism)优于instanceof//员工
interfaceEmployee {
publicintsalary();//工资计算
}
//经理
classManagerimplementsEmployee {
privatestaticfinalintmgrSal= 40000;//工资
publicintsalary() {
returnmgrSal;
}
}
//程序员
classProgrammerimplementsEmployee {
privatestaticfinalintprgSal= 50000;
privatestaticfinalintprgBonus= 10000;//奖金
publicintsalary() {
returnprgSal;
}
publicintbonus() {
returnprgBonus;
}
}
//薪水册
classPayroll {
publicintcalcPayroll(Employee emp) {
intmoney = emp.salary();
if(empinstanceofProgrammer)
//如果是程序员,则计算奖金
money += ((Programmer) emp).bonus();
returnmoney;
}
publicstaticvoidmain(String args[]) {
Payroll pr =newPayroll();
Programmer prg =newProgrammer();
Manager mgr =newManager();
System.out.println("程序员的薪水"+ pr.calcPayroll(prg));
System.out.println("经理的薪水"+ pr.calcPayroll(mgr));
Word-spacing: 0px; text-transform: none; word-break: normal; margin:
新闻热点
疑难解答