java工具类之Arrays、Collections以及比较器

时间:2023-02-24 23:20:50

一、Comparable和Comparator的详解

Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。

(1)Comparable(内比较器)

Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了Comparable接口的类如何比较,则依赖compareTo方法的实现,compareTo方法也被称为自然比较方法。如果开发者add进入一个Collection的对象想要Collections的sort方法帮你自动进行排序的话,那么这个对象必须实现Comparable接口。compareTo方法的返回值是int,有三种情况:

1、比较者大于被比较者(也就是compareTo方法里面的对象),那么返回正整数

2、比较者等于被比较者,那么返回0

3、比较者小于被比较者,那么返回负整数

 public class Domain implements Comparable<Domain>
{
    private String str;
public Domain(String str)
{
    this.str = str;
}
public int compareTo(Domain domain)
{
    if (this.str.compareTo(domain.str) > 0)
        return 1;
    else if (this.str.compareTo(domain.str) == 0)
        return 0;
    else 
        return -1;
}
public String getStr()
{
    return str;
}
}

public static void main(String[] args)
{
    Domain d1 = new Domain("c");
    Domain d2 = new Domain("c");
    Domain d3 = new Domain("b");
    Domain d4 = new Domain("d");
    System.out.println(d1.compareTo(d2));
    System.out.println(d1.compareTo(d3));
    System.out.println(d1.compareTo(d4));
}

(2)Comparator(外比较器)

Comparator可以认为是是一个外比较器,个人认为有两种情况可以使用实现Comparator接口的方式:

1、一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较

2、一个对象实现了Comparable接口,但是开发者认为compareTo方法中的比较方式并不是自己想要的那种比较方式

Comparator接口里面有一个compare方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象,方法返回值和Comparable接口一样是int,有三种情况:

1、o1大于o2,返回正整数

2、o1等于o2,返回0

3、o1小于o3,返回负整数

public class DomainComparator implements     Comparator<Domain>
{
public int compare(Domain domain1, Domain domain2)
{
    if (domain1.getStr().compareTo(domain2.getStr()) > 0)
        return 1;
    else if (domain1.getStr().compareTo(domain2.getStr()) == 0)
        return 0;
    else 
        return -1;
}
}

public static void main(String[] args)
    {
Domain d1 = new Domain("c");
Domain d2 = new Domain("c");
Domain d3 = new Domain("b");
Domain d4 = new Domain("d");
DomainComparator dc = new DomainComparator();
System.out.println(dc.compare(d1, d2));
System.out.println(dc.compare(d1, d3));
System.out.println(dc.compare(d1, d4));
}

(3)总结

总结一下,两种比较器Comparable和Comparator,后者相比前者有如下优点:

1、如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法

2、实现Comparable接口的方式比实现Comparator接口的耦合性 要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修 改。从这个角度说,其实有些不太好,尤其在我们将实现类的.class文件打成一个.jar文件提供给开发者使用的时候。实际上实现Comparator 接口的方式后面会写到就是一种典型的策略模式。

二、Arrays类详解

java.util.Arrays类是JDK提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用

常用方法

asList

作用是返回由指定数组支持的固定大小列表

注意:这个方法返回的ArrayList 不是我们常用的集合类 java.util.ArrayList。这里的 ArrayList 是 Arrays 的一个内部类 java.util.Arrays.ArrayList。(返回的 ArrayList 数组是一个定长列表,我们只能对其进行查看或者修改,但是不能进行添加或者删除操作)

List<String> listStr = new ArrayList<>(Arrays.asList(str));

sort

该方法是用于数组排序,在Arrays类中有该方法的一系列重载方法,能对7种基本数据类型,包括 byte,char,double,float,int,long,short 等都能进行排序,还有 Object 类型(实现了Comparable接口),以及比较器 Comparator 。

binarySearch

用二分法查找数组中的某个元素,该方法和sort方法一样,适用于各种基本数据类型以及对象

注意:二分法是对以及有序的数组进行查找(比如先用Arrays.sort()进行排序,然后调用此方法进行查找)。找到元素返回下标,没有则返回 -1

copyOf

拷贝数组元素。底层采用 System.arraycopy() 实现,这是一个native方法。

equals和deepEquals

equals 用来比较两个数组中对应位置的每个元素是否相等。

deepEquals也是用来判断比较两个数组的元素是否相等,不过 deepEquals 能够进行比较多维数组,而且是任意层次的嵌套数组。

String[][] name1 = {{ "G","a","o" },{ "H","u","a","n"},{ "j","i","e"}};  
String[][] name2 = {{ "G","a","o" },{ "H","u","a","n"},{ "j","i","e"}};
System.out.println(Arrays.equals(name1,name2));// false  
System.out.println(Arrays.deepEquals(name1,name2));// true

fill

该系列方法用于给数组赋值,并能指定某个范围赋值。

toString和deepToString

toString 用来打印一维数组的元素,而 deepToString 用来打印多层次嵌套的数组元素。

三、Collections类详解

Collections是集合类的一个工具类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作

排序方法

Collections提供了以下方法对List进行排序

void reverse(List list):反转

void shuffle(List list),随机排序

void sort(List list),按自然排序的升序排序

void sort(List list, Comparator c);定制排序,由Comparator控制排序逻辑

void swap(List list, int i , int j),交换两个索引位置的元素

void rotate(List list, int distance),旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面。

sort

看一下sort(List list)源码

    public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

list接口里的sort方法

    default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

查找,替换操作

int binarySearch(List list, Object key), 对List进行二分查找,返回索引,注意List必须是有序的

int max(Collection coll),根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)

int max(Collection coll, Comparator c),根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c)

void fill(List list, Object obj),用元素obj填充list中所有元素

int frequency(Collection c, Object o),统计元素出现次数

int indexOfSubList(List list, List target), 统计targe在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target).

boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替换旧元素。

同步控制

Collections中几乎对每个集合都定义了同步控制方法,例如 SynchronizedList(), SynchronizedSet(),SynchronizedMap()等方法,来将集合包装成线程安全的集合。