[Java] 集合类克隆方法与内部排序

写在前面

* 文章中的示例类 Point 类(已省略 get、set 方法),函数 generatePoint 的意义为随机生成指定个数的点集。Point 类实现了 Cloneable 接口并重载了 clone 函数。

Point 类

注意在获取随机数时,要将 (Math.random( ) * 101) 作为一个整体括起来。


克隆方法 clone( )

  • 当将对象存入集合 A 后,集合拥有的只是对象的引用而非其本身,所以在将 A 赋值给 B 集合后,修改 B 中任何对象都会对 A 集合中相应对象产生影响
    • 使用场景:如在求凸包问题时,需要利用同一点集进行分治、Graham Scan、暴力法等多种方法进行求解,而不同方法求解过程中可能会对集合顺序或集合内容进行修改影响其他方法的结果,所以需要将同一点集克隆几份供不同方法使用。但单纯的复制(赋值)方法只能将赋值引用,指向的仍然是同一对象。
  • 克隆浅拷贝
    • 直接对 Point 类进行克隆可以实现复制一份新对象
      • Shallow Copy Code
    • 默认的克隆操作是浅拷贝,它并没有克隆包含在对象中的内部对象。
      • 虽然可实现目的,但是假设 Point 类的实例域还包含除 x、y 这样基本类型外的引用类型实例,那么使用浅克隆则不会克隆这些引用。如引入类 A 并加入到 Point 类的实例中,改变 p1 中的 A1 时也会导致 p1’ 中的 A1 改变
        • Shallow Copy
  • 克隆深拷贝
    • 让该类所包含的内部对象所在类 A 实现 Cloneable 接口,并在 Point 类的 clone( ) 方法中显式克隆 A 对象。
      • clone()
    • 深拷贝后可实现内部对象的克隆
      • Deep Copy
    • 我认为应尽量避免使用克隆,因为一旦有其他类(如极坐标系下的点 PolarPoint 类)继承了 Point 类,那么任何对象都可以都可以利用 Point 类克隆 PolarPoint 类,所以应该谨慎的实现子类的克隆。
      • 替代方案
        • 使用迭代器或 for 循环,一个个去取集合中的元素,然后挨个属性赋值给另一个新对象,在赋值过程中就可以自定义其中的内部对象的拷贝方式。

集合内部排序

  • 使用 Collections.sort( ) 方法前的两种可选方案
    • 实现 Comparable 接口
    • 实现 Comparator 接口
  • 方法一:实现 Comparable 接口
    • 适用范围:Comparable 接口被用来提供对象的自然排序,我们可以使用它来提供基于单个逻辑的排序。
    • 需要重载 compareTo< T > 方法
    • 自然排序与 equals 一致:对于类 C 的每一个 e1 和 e2 来说,当且仅当 (e1.compareTo((Object)e2) == 0) 与e1.equals((Object)e2) 具有相同的布尔值
    • 对于自己想比较的实例域,可以通过重写 equals 方法和改写对象 HashCode 生成方法来实现
      • 例如,想让 Point 点集在调用 Collections.sort( ) 时按照 x 大小排序
        • 1、告诉 equals 函数应按照什么来判断两个点算相等 (默认来说,equals 函数会按照两个比较内容的哈希值进行比较,而两个对象的哈希值虽不相等但可能两个点的 x、y 值都对应相等)
          • Step1
        • 2、告诉 compareTo 函数怎么比较大小 (实际调用时的样子是这样的:p1.compareTo( p2 ),所以 this.getX( ) 即是 p1 的 x 值,返回正数代表 p1 的 x 大)
          • Step2
    • 排序时
      • 升序:Collections.sort ( pList )
      • 降序:Collections.sort ( pList, Collections.reverseOrder( ) )
  • 方法二:实现 Comparator 接口
    • 适用范围:Comparator 接口被用来提供不同的排序算法,我们可以选择需要使用的 Comparator 来对给定的对象集合进行排序。
      • 我感觉 Comparator 更好
    • 需要提供一个排序类(可以为匿名类)并实现 Comparator 接口
      • 从上面的 Comparable 可以看出,它需要让 Point 类去实现接口。如果类的设计人员并没有这样做,则需要使用 Comparator
      • 此外,如果想让 Comparable 内部的 compareTo 函数来实现依据不同逻辑提供不同排序操作(如有的时候需要按照 x 大小排序,但有时需要按 y 大小排序)的话有些牵强
      • 所以,假设 Point 类没有实现 Comparable 接口,我们可以自己设两个比较器类 PointSortByX 和 PointSortByY 且都实现 Comparator 接口,并分别在其中给出 compare 方法
    • 例1:把集合 pList 中的点集先按 x 大小排序,再按 y 大小排序(我分别用新建比较器类和匿名类的方法实现)
      • 1、创建比较器类
        • Step1
      • 2、按 x 大小排序,注意 Collections.sort 还有一个构造器可接受一个 Comparator 参数
        • 这里写图片描述
      • 3、使用匿名类创建按 y 大小比较的比较器
        • 这里写图片描述
    • 例2:把集合 pList 中的点集按照 x 大小进行排序,如果 x 值相等则按 y 排序
      • 创建比较器类
        • 这里写图片描述
      • 调用 Collections.sort( pList, new PointSortByX_Y( ) ); 即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值