跳到主要内容

Java 变量

变量 (Variable) 是为我们储存临时数据的解决方案。

一个简单的变量定义如下:

Object obj;

这是一个很有意思的代码,因为它定义的变量 obj 兼容性极强。

你可以给这个变量赋值,像这样:

obj = null; // null
obj = 0; // int
obj = 0D; // double
obj = 0L; // long
obj = 0F; // float
obj = ""; // java.lang.String
Object anotherObj;
obj = anotherObj; // 这个变量将最终指向另一个变量

变量之间的赋值,又分为软复制硬复制

什么是软复制呢?就是指一个变量的指针 (内存地址,对于每一种语言都基于此在内存储存变量) 被赋予到目标变量,引用目标变量是实际上最终引用的是一开始的变量。像这样:

class Student {
String name;

Student(String name) {
this.name = name;
}
}

public static void main(String[] args) {
Student a = new Student("A 学生");
Student b = a;
b.name = "B 学生";
}

按预期运行的话,此处 b 变量的 name 属性的值应该为 "B 学生" ,的确如此。

你也可能会认为此处 a 变量的 name 属性的值应该还是原先的 "A 学生" 。但是,这是错误的。实际上, a 变量的 name 属性的值也已经在语句 b.name = "B 学生"; 执行完毕后也变成了 "B 学生"

因为两个变量实际上用的都是一个 Student 对象,为了验证,你可以在此之后加上:

System.out.println(a);
System.out.println(b);

结果显而易见,当你调用方法 System.out.println 时,此方法将传入的值 a b 分别调用了共同的方法 toString ,你会看到控制台输出的结果是:

coolclk.tutorial.Main.Student@114514
coolclk.tutorial.Main.Student@114514

完全相同,在 @ 后的内容是每个对象独立的 hashCode ,也验证了上方的说法。

那么,该怎么解决这个问题呢?

你可以进行 硬复制 ,但除 基元数据 和其它特殊数据外,你仍需要自己实现这个过程。

对于同一包下的类,你可以在原先基础上做出改变,像这样:

class Student implements Cloneable {
String name;

Student(String name) {
this.name = name;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return new Student(this.name);
}
}

public static void main(String[] args) {
Student a = new Student("A 学生");
Student b = (Student) a.clone(); // 此处方法的调用是必须的
b.name ="B 学生";
}

完成~ 你也可以另外写一个方法,就像上面那样,优点是支持跨包,缺点是针对完美主义者。