1. 目的
本文通过简单的示例,阐述Java中对象的概念,避免TXs犯类似的错误。
本文的代码示例均来源于实际产品的遗留代码,但抽象为更加简单易懂的例子。
2. 示例1
先看一段代码,其主要意思是替换列表中某个元素的属性。
2.1 Student.java
public class Student {
int id;
private String name = null;
int score;
public Student(int id, String name, int score) {
this.id = id;
this.name = name;
this.score = score;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String toString() {
return "Student[id=" + id
+ ", name=" + name
+ ", score=" + score
+ ", hashCode=" + hashCode()
+ "]";
}
}
2.2 StudentObjects.java
import java.util.ArrayList;
import java.util.List;
public class StudentObjects {
private List<Student> students = new ArrayList<Student>();
private void dumpObjects() {
for (Student s : students) {
System.out.println(s);
}
}
private void addSomeObjects() {
students.add(new Student(1, "first", 10));
students.add(new Student(2, "second", 20));
students.add(new Student(3, "third", 30));
}
private void updateObject() {
int id = 2;
for (Student s : students) {
if (s.getId() == id) {
Student temp = s;
temp.setScore(200);
students.add(students.indexOf(s), temp);
students.remove(s);
return;
}
}
}
private static void test() {
StudentObjects objects = new StudentObjects();
objects.addSomeObjects();
objects.dumpObjects();
objects.updateObject();
objects.dumpObjects();
}
public static void main(String[] args) {
test();
}
}
2.3 运行结果
Student[id=1, name=first, score=10, hashCode=31168322]
Student[id=2, name=second, score=20, hashCode=17225372]
Student[id=3, name=third, score=30, hashCode=5433634]
Student[id=1, name=first, score=10, hashCode=31168322]
Student[id=2, name=second, score=200, hashCode=17225372]
Student[id=3, name=third, score=30, hashCode=5433634]
2.4 分析
我们要讨论的是上述代码中的updateObjects()方法。
这里的替换或更改属性的算法,是典型的对于Java对象不慎理解的情形。变量temp和s其实指向的是同一个对象,因此在列表中add&remove完全是不必要的操作。
为了更加明确说明对象的概念,我们在toString()中把hashCode也打印出来了,可以看出,temp和s其实完全是heap中的同一个对象。
2.5 改进的代码
private void goodUpdateObject() {
int id = 2;
for (Student s : students) {
if (s.getId() == id) {
s.setScore(200);
return;
}
}
}
3. 题外话
通过本文的例子,可以发现写这个代码的TX知道的东西很多,包括add, indexOf, remove。由此说明,对相关知识点(比如List)还是做了相当的功课。但是否这样的代码就是我们提倡的呢?答案显然是否定的。
- 我们需要的是简单的算法、简单明了的代码,越简单越好,因为代码是写给人看的,而不是计算机看的。
- 通过复杂的算法去完成了简单的任务,是在制造问题,而不是解决问题。——因为让维护人员看着诡异。
- 诡异的代码无形中增加了程序的运行成本,即恶化了程序的性能。现在的软件产品的规模通常都是以10KLOC为单位,在这种规模的软件中,如果处处都充斥着本文类似的编写方式,可想对产品的性能会有多大的冲击。——对于smart phone就是影响其续航能力。