1. 导读
上期分享了本人关于String四个问题, 本期我们继续探讨String中的两个问题:
.1 String既然已经实现了Comparable接口, 为什么还要提供内部类----CaseInsensitiveComparator;
.2 使用 "+" 拼接String究竟干了什么? 为什么在循环中不让使用"+"拼接String;
2. String为什么要提供内部类CaseInsensitiveComparator
先来看下String实现了Comparable接口后做了什么:
String::compareTo做了三件事:
.1 比较两个字符串的长度, 找出最小值;
.2 比较最小长度中的字符是否相同, 因底层使用ASCII码存储, 10进制的ASCII是纯数字, 可直接减得出比较结果(compareTo规定: 返回-1是小于; 0是等于; 1是大于);
.3 如果最小长度的字符都相同, 再比较两个字符串的长度是否相同;
字符串是可能含有大小写的, 在String::compareTo中认为A和a是不同的, 那么在忽略大小写的场景中就不适用了;既然String提供了基于Comparator的内部类, 是不是对这种场景做了特殊处理呢?我们接下来看CaseInsensitiveComparator的核心实现:
可以看到compare的逻辑和String:compareTo大同小异, 只是在第二步的时候做了特殊处理:
.1 先将char字符转换成大写作比较(如果是数字则不变);
.2 如果大写比较不符, 再转换成小写做比较;
.3 如果小写比较还是不符, 证明该char字符为数字, 直接比较即可;
上面只是说明了这两者实现的不同, 还是没有说明为什么这么实现; 要解答这个首先需要说明下Comparable 和Comparator的异同:
.1 两者都是接口, 都是实现对象的比较的, 返回值都是{-1, 0, 1};
.2 Comparable需要重写Comparable::compareTo方法, 会对比较对象的代码形成侵入; Comparator由一个比较目标对象的策略类来实现, 同时比较策略则由编写者指定, 无需侵入比较对象的代码;故而String实现Comparable接口提供了一种内排序的方式, 而Comparator提供了一种不改变比较对象代码, 实现比较的策略, 如果对CaseInsensitiveComparator的实现并不满意, 也可以自己实现MySelfComparator;
划重点:
.1 CaseInsensitiveComparator的实现只是String作者提供了一种不同于String::compareTo的比较策略, 如果说Compareable是比较的内部实现, 那么Comparator就是比较的外部实现;
.2 Comparator这种方式实现了策略模式, 将变与不变完美分类; 关于设计模式后面再开专题分享;
.3 Comparator接口中还有个equals方法没有实现, 不实现这个方法为什么不报错呢? 因为所有类的父类都是Object,Object::equals已经对这个方法做了实现, 也就不报错了;
.4 如果Compareable::compareTo 或者 Comparator::compare的实现的比较结果与equals不符时, 你需要考虑这种情况会不会有影响;比如HashMap中先调用equals再调用的compareTo, 这时候如果equals与compareTo的结果是不一致, 不就引起问题了; 虽然实现了Compareable接口不强制重写equals方法, 但是不一致的情况还是需要考虑下的;
3. String字符串拼接的三种方式比较
对于字符串拼接, 我们可以使用一下三种方式:
.1 "+