对象的排序和拷贝
对象,是一种非常普遍的数据模型,值得玩味。本篇将对比Java
和JavaScript
两门语言中,对对象进行基本操作的异同之处。
排序
排序是一个简单的操作,但对数组中的对象进行排序,使其按照某种属性排序,则需要进行一些额外的处理。来看一个例子,现在有一些员工,需要对这些员工的薪水进行升序排序。在JavaScript中:
class Employee {
constructor(name, salary) {
this.name = name
this.salary = salary
}
getName() {
return this.name
}
getSalary() {
return this.salary
}
}
const staff = []
staff[0] = new Employee('Foo', 35000)
staff[1] = new Employee('Bar', 21000)
staff[2] = new Employee('Tony', 39000)
staff.sort((first, second) => {
return first.salary - second.salary
})
console.log(staff)
数组自带排序方法,但是数组的默认排序方法是按照字典顺序(字母顺序)来排序的。如果要对其salary属性进行排序,则需要自定义一个比较函数,传入到sort方法中。
在Java语言中,处理是类似的。但是,在定义的Employee类中,必须要实现Coparable接口中的compareTo方法:
public class Employee implements Comparable<Employee> {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
// 要让一个类使用排序,必须让它实现compareTo
public int compareTo(Employee other) {
return Double.compare(salary, other.salary);
}
}
然后,直接使用Arrays.sort(staff)
进行排序即可:
import java.util.Arrays;
public class EmployeeSortTest {
public static void main(String[] args) {
var staff = new Employee[3];
staff[0] = new Employee("Foo", 35000);
staff[1] = new Employee("Bar", 21000);
staff[2] = new Employee("Tony", 39000);
Arrays.sort(staff);
for(Employee e: staff)
System.out.println("name=" + e.getName() + ", salary=" + e.getSalary());
}
}
对比下来,Java中的代码略显冗长。
拷贝
对象拷贝有两种类型,一种是浅拷贝
,一种是深拷贝
,我们来看看这两者的区别。先来看浅拷贝。
浅拷贝非常简单,对于JavaScript而言:
const obj = {
name: 'Foo',
age: 30,
score: {
math: 80,
chinese: 60
},
id: Symbol('uuid')
}
const obj2 = obj
直接通过赋值即可浅拷贝。而在Java中,也是通过直接赋值来进行浅拷贝。但深拷贝就稍显麻烦了,对于JavaScript来说,需要遍历对象的所有属性,然后逐一赋值,这里写了一个简单的函数来进行相关处理:
function deepCopy(obj) {
const result = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
result[key] = deepCopy(obj[key])
} else {
result[key] = obj[key]
}
}
}
return result
}
如果要深拷贝:
const copyObj = deepCopy(obj)
但是如果是很简单的对象,JSON.stringfy()和JSON.parse()就可搞定。但是这种简单粗暴的方法有其局限性。当值为undefined
、function
、symbol
会在转换过程中被忽略。所以,稍微复杂点的对象还是需要用deepCopy工具函数来进行深拷贝。
而对于Java而言,需要让其对象的类实现Cloneable
接口,这里给出部分核心代码:
class Employee implements Cloneable {
public Employee clone() throws CloneNotSupportedException {
Employee cloned = (Employee) super.clone();
return cloned;
}
}
然后,再使用:
var obj = new Employee('Foo', 30000);
Employee copyObj = obj.clone();
小结
对比一下这两种语言的实现,发现它们之间差别挺大的,主要是因为JavaScript是脚本语言,拥有其独特的灵活性,而Java是纯粹的面向对象语言,功能实现都需要围绕类和对象进行设计,所以,看上去就显得冗长啰嗦。
参考
- Cay S. Horstmann, Core Java Volume I - Fundamentals(Eleventh Edition)