赋值是用等号运算符(=)进行的它的意思是取得右边的值把它复制到左边右边的值可以是任何常数变量或者表达式只要能产生一个值就行但左边的值必须是一个明确的已命名的变量也就是说它必须有一个物理性的空间来保存右边的值举个例子来说可将一个常数赋给一个变量(A=;)但不可将任何东西赋给一个常数(比如不能=A)
对主数据类型的赋值是非常直接的由于主类型容纳了实际的值而且并非指向一个对象的句柄所以在为其赋值的时候可将来自一个地方的内容复制到另一个地方例如假设为主类型使用A=B那么B处的内容就复制到A若接着又修改了A那么B根本不会受这种修改的影响作为一名程序员这应成为自己的常识
但在为对象赋值的时候情况却发生了变化对一个对象进行操作时我们真正操作的是它的句柄所以倘若从一个对象到另一个对象赋值实际就是将句柄从一个地方复制到另一个地方这意味着假若为对象使用C=D那么C和D最终都会指向最初只有D才指向的那个对象下面这个例子将向大家阐示这一点
这里有一些题外话在后面大家在代码示例里看到的第一个语句将是package 使用的package语句它代表本书第章本书每一章的第一个代码清单都会包含象这样的一个package(封装打包包裹)语句它的作用是为那一章剩余的代码建立章节编号在第章大家会看到第章的所有代码清单(除那些有不同封装名称的以外)都会自动置入一个名为c的子目录里第章的代码置入c以此类推所有这些都是通过第章展示的CodePackagejava程序实现的封装的基本概念会在第章进行详尽的解释就目前来说大家只需记住象package 这样的形式只是用于为某一章的代码清单建立相应的子目录
为运行程序必须保证在classpath里包含了我们安装本书源码文件的根目录(那个目录里包含了cccc等等子目录)
对于Java后续的版本(和更高版本)如果您的main()用package语句封装到一个文件里那么必须在程序名前面指定完整的包裹名称否则不能运行程序在这种情况下命令行是
java cAssignment
运行位于一个包裹里的程序时随时都要注意这方面的问题
下面是例子
//: Assignmentjava
// Assignment with objects is a bit tricky
package c;
class Number {
int i;
}
public class Assignment {
public static void main(String[] args) {
Number n = new Number();
Number n = new Number();
ni = ;
ni = ;
Systemoutprintln(: ni: + ni +
ni: + ni);
n = n;
Systemoutprintln(: ni: + ni +
ni: + ni);
ni = ;
Systemoutprintln(: ni: + ni +
ni: + ni);
}
} ///:~
Number类非常简单它的两个实例(n和n)是在main()里创建的每个Number中的i值都赋予了一个不同的值随后将n赋给n而且n发生改变在许多程序设计语言中我们都希望n和n任何时候都相互独立但由于我们已赋予了一个句柄所以下面才是真实的输出
: ni: ni:
: ni: ni:
: ni: ni:
看来改变n的同时也改变了n!这是由于无论n还是n都包含了相同的句柄它指向相同的对象(最初的句柄位于n内部指向容纳了值的一个对象在赋值过程中那个句柄实际已经丢失它的对象会由垃圾收集器自动清除)
这种特殊的现象通常也叫作别名是Java操作对象的一种基本方式但假若不愿意在这种情况下出现别名又该怎么操作呢?可放弃赋值并写入下述代码
ni = ni;
这样便可保留两个独立的对象而不是将n和n绑定到相同的对象但您很快就会意识到这样做会使对象内部的字段处理发生混乱并与标准的面向对象设计准则相悖由于这并非一个简单的话题所以留待第章详细论述那一章是专门讨论别名的其时大家也会注意到对象的赋值会产生一些令人震惊的效果
方法调用中的别名处理
将一个对象传递到方法内部时也会产生别名现象
//: PassObjectjava
// Passing objects to methods can be a bit tricky
class Letter {
char c;
}
public class PassObject {
static void f(Letter y) {
yc = z;
}
public static void main(String[] args) {
Letter x = new Letter();
xc = a;
Systemoutprintln(: xc: + xc);
f(x);
Systemoutprintln(: xc: + xc);
}
} ///:~
在许多程序设计语言中f()方法表面上似乎要在方法的作用域内制作自己的自变量Letter y的一个副本但同样地实际传递的是一个句柄所以下面这个程序行
yc = z;
实际改变的是f()之外的对象输出结果如下
: xc: a
: xc: z
别名和它的对策是非常复杂的一个问题尽管必须等至第章才可获得所有答案但从现在开始就应加以重视以便提早发现它的缺点