对象的排序和拷贝

阅读 1.8k

对象,是一种非常普遍的数据模型,值得玩味。本篇将对比JavaJavaScript两门语言中,对对象进行基本操作的异同之处。

排序

排序是一个简单的操作,但对数组中的对象进行排序,使其按照某种属性排序,则需要进行一些额外的处理。来看一个例子,现在有一些员工,需要对这些员工的薪水进行升序排序。在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()就可搞定。但是这种简单粗暴的方法有其局限性。当值为undefinedfunctionsymbol会在转换过程中被忽略。所以,稍微复杂点的对象还是需要用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)
最后编辑于: 2022-06-28

评论(0条)

(必填)
复制成功