复杂大型网站建设成本,资料代做网站,玄武建设局网站,附近企业建站公司对象排序List l可以如下排序。Collections.sort(l);如果List包含String元素#xff0c;它将按字母顺序排序#xff0c;如果它由Date元素组成#xff0c;它将按时间顺序排序#xff0c;这是怎么发生的#xff1f;String和Date都实现了Comparable接口#xff0c;Comparable…对象排序List l可以如下排序。Collections.sort(l);如果List包含String元素它将按字母顺序排序如果它由Date元素组成它将按时间顺序排序这是怎么发生的String和Date都实现了Comparable接口Comparable实现为类提供了自然的顺序允许该类的对象自动排序下表总结了一些实现Comparable的更重要的Java平台类。类自然排序Byte有符号数字Character无符号数字Long有符号数字Integer有符号数字Short有符号数字Double有符号数字Float有符号数字BigInteger有符号数字BigDecimal有符号数字BooleanBoolean.FALSE Boolean.TRUEFile依赖于系统的路径名称上的字典String接字母顺序Date按时间顺序CollationKey特定于语言环境的字典如果你尝试对列表进行排序其中的元素未实现ComparableCollections.sort(list)将抛出ClassCastException类似地如果你尝试使用comparator对其元素无法相互比较的列表进行排序则Collections.sort(list, comparator)将抛出ClassCastException。虽然不同类型的元素可以相互比较但这里列出的类别都不允许进行类间比较。如果你只想对可比较元素的列表进行排序或创建它们的已排序集合那么你真正需要了解Comparable接口的所有内容如果要实现自己的Comparable类型下一部分将是你感兴趣的。编写自己的Comparable类型Comparable接口包含以下方法。public interface Comparable {public int compareTo(T o);}compareTo方法将接收对象与指定对象进行比较并返回负整数、0或正整数具体取决于接收对象是否小于、等于或大于指定对象如果无法将指定的对象与接收对象进行比较则该方法将抛出ClassCastException。以下表示人名的类实现了Comparable。import java.util.*;public class Name implements Comparable {private final String firstName, lastName;public Name(String firstName, String lastName) {if (firstName null || lastName null)throw new NullPointerException();this.firstName firstName;this.lastName lastName;}public String firstName() { return firstName; }public String lastName() { return lastName; }public boolean equals(Object o) {if (!(o instanceof Name))return false;Name n (Name) o;return n.firstName.equals(firstName) n.lastName.equals(lastName);}public int hashCode() {return 31*firstName.hashCode() lastName.hashCode();}public String toString() {return firstName lastName;}public int compareTo(Name n) {int lastCmp lastName.compareTo(n.lastName);return (lastCmp ! 0 ? lastCmp : firstName.compareTo(n.firstName));}}为了使前面的例子简短该类有些限制它不支持中间名它要求名字和姓氏并且它不以任何方式国际化尽管如此它还说明了以下要点Name对象是不可变的在所有其他条件相同的情况下不可变类型是解决问题的方法特别是对于将作为集合中的元素或Map中的键使用的对象如果你在集合中修改元素或键这些集合将会中断。构造函数检查其参数是否为null这可以确保所有Name对象都格式正确这样其他任何方法都不会抛出NullPointerException。hashCode方法被重新定义这对于重新定义equals方法的任何类都是必不可少的(等同对象必须具有相同的哈希码)。如果指定的对象为null或类型不合适则equals方法返回falsecompareTo方法在这些情况下抛出运行时异常这两种行为都是各自方法的一般契约所要求的。toString方法已重新定义因此它以人类可读的形式打印Name这总是一个好主意特别是对于要放入集合的对象各种集合类型的toString方法依赖于其元素、键和值的toString方法。由于本节是关于元素排序的让我们再谈谈Name的compareTo方法它实现了标准的名称排序算法其中姓氏优先于名字这正是你想要的自然顺序如果自然顺序不自然那将会非常混乱看看compareTo是如何实现的因为它非常经典首先比较对象的最重要部分(在本例中为姓氏)通常你可以只使用部分类型的自然顺序在这种情况下该部分是一个字符串自然(词典)排序正是所要求的。如果比较的结果不是0(代表相等)那么就完成了你只需返回结果。如果最重要的部分相同则继续比较下一个最重要的部分在这种情况下只有两个部分 — 名字和姓氏。如果有更多的部分你会以明显的方式进行比较部分直到你发现两个不相等或你正在比较最不重要的部分此时你将返回比较的结果。为了说明这一切都是有效的这里有一个程序它构建了一个名称列表并对它们进行排序。import java.util.*;public class NameSort {public static void main(String[] args) {Name[] nameArray {new Name(John, Smith),new Name(Karl, Ng),new Name(Jeff, Smith),new Name(Tom, Rich)};List names Arrays.asList(nameArray);Collections.sort(names);System.out.println(names);}}如果你运行这个程序这是它打印的内容。[Karl Ng, Tom Rich, Jeff Smith, John Smith]compareTo方法的行为有四个限制我们现在不会讨论它们因为它们相当技术性和枯燥最好留在API文档中实现Comparable的所有类都遵守这些限制非常重要因此如果你正在编写实现它的类请阅读Comparable的文档。尝试对违反限制的对象列表进行排序具有未定义的行为从技术上讲这些限制确保自然顺序是实现它的类的对象的总顺序这对于确保明确定义排序是必要的。Comparators如果你想按一些对象的自然顺序以外的顺序排序该怎么办或者如果要对某些未实现Comparable的对象进行排序该怎么办要执行上述任一操作你需要提供Comparator — 一个封装排序的对象与Comparable接口一样Comparator接口由单个方法组成。public interface Comparator {int compare(T o1, T o2);}compare方法比较它的两个参数返回一个负整数、0或一个正整数具体取决于第一个参数是小于、等于还是大于第二个参数如果其中一个参数的Comparator类型不合适则compare方法将抛出ClassCastException。关于Comparable的大部分内容也适用于Comparator编写compare方法与编写compareTo方法几乎完全相同只是前者将两个对象作为参数传入由于同样的原因compare方法必须遵守与Comparable的compareTo方法相同的四个技术限制 — Comparator必须对它所比较的对象产生总顺序。假设你有一个名为Employee的类如下所示。public class Employee implements Comparable {public Name name() { ... }public int number() { ... }public Date hireDate() { ... }...}让我们假设Employee实例的自然顺序是员工姓名上的Name排序(如上例所定义)不幸的是老板要求按照资历顺序列出员工名单。这意味着我们必须做一些工作但并不多以下程序将生成所需的列表。import java.util.*;public class EmpSort {static final Comparator SENIORITY_ORDER new Comparator() {public int compare(Employee e1, Employee e2) {return e2.hireDate().compareTo(e1.hireDate());}};// Employee databasestatic final Collection employees ... ;public static void main(String[] args) {List e new ArrayList(employees);Collections.sort(e, SENIORITY_ORDER);System.out.println(e);}}程序中的Comparator相当简单它依赖于应用于hireDate访问器方法返回的值的Date的自然顺序注意Comparator将第二个参数的雇用日期传递给第一个参数而不是反过来原因是最近招聘的员工级别最低按雇用日期顺序排序会使该名单的资历顺序相反人们有时用来达到这种效果的另一种技术是保持参数顺序但要否定比较的结果。// Dont do this!!return -r1.hireDate().compareTo(r2.hireDate());你应该总是使用前一种技术来支持后者因为后者不能保证有效这样做的原因是compareTo方法可以返回任何负整数如果它的参数小于调用它的对象。有一个负整型数在被否定时仍然是负的尽管这看起来很奇怪。-Integer.MIN_VALUE Integer.MIN_VALUE上一个程序中的Comparator可以很好地对List进行排序但确实存在一个缺陷它不能用于排序已排序的集合例如TreeSet因为它生成的顺序与equals不兼容这意味着这个Comparator相当于equals方法所没有的对象。特别是在同一天雇佣的任何两名员工将相等当你对List进行排序时这并不重要但是当你使用Comparator来排序一个已排序的集合时它是致命的如果你使用此Comparator将在同一日期雇用的多名员工插入到TreeSet中则只会将第一个员工添加到该集合中第二个将被视为重复元素将被忽略。要解决此问题只需调整Comparator以便生成与equals兼容的排序换句话说调整它以便在使用compare时看到相同的唯一元素是那些在使用equals进行比较时也被视为相等的元素。执行此操作的方法是执行两部分比较(像对于Name)其中第一部分是我们感兴趣的部分 — 在这种情况下是雇用日期 — 第二部分是唯一标识对象的属性员工编号在这里是明显的属性这是比较器的结果。static final Comparator SENIORITY_ORDER new Comparator() {public int compare(Employee e1, Employee e2) {int dateCmp e2.hireDate().compareTo(e1.hireDate());if (dateCmp ! 0)return dateCmp;return (e1.number() e2.number() ? -1 :(e1.number() e2.number() ? 0 : 1));}};最后一点你可能想要使用更简单的方法替换Comparator中的最终return语句return e1.number() - e2.number();除非你绝对确定没有人会有负的员工编号否则不要这样做这个技巧通常不起作用因为带符号整数类型不够大不能表示两个任意带符号整数的差如果i是一个大的正整数且j是一个大的负整数i - j将溢出并返回一个负整数由此产生的comparator违反了我们一直在讨论的四个技术限制之一(传递性)并产生可怕的、微妙的错误这不是纯粹的理论问题。