容器

1.Java容器类图


容器_第1张图片
Java容器类图

Collection:一个独立元素的序列,这些元素都服从一条或多条规则。
List必须按照插入的顺序保存元素,而Set不能有重复元素,Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。

Map:一组成对的"键值对"对象,允许你使用键来查找值。

Java SE5新添加了:
Queue接口(LinkedList已经为实现该接口做了修改)及其实现;
PriorityQueue和各种风格的BlockingQueue;
ConcurrentMap接口及其实现ConcurrentHashMap,它们也是用于多线程机制的;
CopyOnWriteArrayList和CopyOnWriteArraySet,它们也是用于多线程机制的;
EnumSet和EnumMap,为使用enum而设计的Set和Map的特殊实现;
在Collections类中的多个便利方法。

2.向上转型可以像作用于其他类型一样作用于泛型。

public class A {}
public class B extends A {}
public class C extends A {}

ArrayList list = new ArrayList<>();
list.add(new B());
list.add(new C());
for(A a : list) {
    Log.d(TAG, "zwm, a: " + a);
}

//输出
zwm, a: com.tomorrow.test20181228.MainActivity$B@e579703
zwm, a: com.tomorrow.test20181228.MainActivity$C@aa06680

3.容器类向上转型

List list = new ArrayList<>(); //ArrayList向上转型为List
List list = new LinkedList<>(); //LinkedList向上转型为List

应该创建一个具体的类对象,将其转型为对应的接口,然后在其余的代码中都使用这个接口。但是这种方法并非总能奏效,因为某些类具有额外的功能,例如,LinkedList具有在List接口中未包含的额外方法,而TreeMap也具有在Map接口中未包含的方法。如果你需要使用这些方法,就不能将它们向上转型为更通用的接口。

4.在java.util包中的Arrays和Collections类中都有很多实用方法,可以在一个Collection中添加一组元素。

Arrays.asList()方法接受一个数组或是一个用逗号分隔的元素列表(使用可变参数),并将其转换为一个List对象。
注意:Arrays.asList()输出的List对象,其底层表示的是数组,因此不能调整尺寸,如果你视图用add()或delete()方法在这种列表中添加或删除元素,就有可能会引发去改变数组尺寸的尝试,在运行时会获得"Unsupported Operation(不支持的操作)"错误。

Collections.addAll()方法接受一个Collection对象,以及一个数组或是一个用逗号分隔的列表,将元素添加到Collection中。

Collection的构造器可以接受另一个Collection,用它来将自身初始化,因此可以使用Arrays.asList()来为这个构造器产生输入。

Collection的addAll()方法只能接受另一个Collection对象作为参数。

5.容器的打印
默认的打印行为(使用容器提供的toString()方法)即可生成可读性很好的结果。Collection打印出来的内容用方括号括住,每个元素由逗号分隔。Map则用大括号括住,键与值由等号联系(键在等号左边,值在右边)。

List list = new ArrayList<>();
list.add(1);
list.add(2);
Log.d(TAG, "zwm, list: " + list);

Map map = new HashMap<>();
map.put(1, "a");
map.put(2, "b");
Log.d(TAG, "zwm, map: " + map);

//输出
zwm, list: [1, 2]
zwm, map: {1=a, 2=b}

6.List
List接口在Collection的基础上添加了大量的方法,使得可以在List的中间插入和删除元素。有两种类型的List:
基本的ArrayList,长于随机访问元素,但是在List的中间插入和删除元素时较慢。
LinkedList,通过代价较低的在List中间进行的插入和删除操作,提供了优化的顺序访问,但是在随机访问方面相对比较慢。
LinkedList还添加了可以使其用作栈、队列或双端队列的方法。

7.迭代器
迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必知道或关心该序列底层的结构。

Java的Iterator只能单向移动,用法如下:
(1)使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
(2)使用next()获得序列中的下一个元素。
(3)使用hasNext()检查序列中是否还有元素。
(4)使用remove()将迭代器新近返回的元素删除。

List list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); 
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
    Integer item = iterator.next();
    Log.d(TAG, "zwm, item: " + item);
}

for(Integer item : list) {
    Log.d(TAG, "zwm, item: " + item);   
}

iterator = list.iterator();
for(int i=0; i<3; i++) {
    iterator.next();
    iterator.remove();
}

Log.d(TAG, "zwm, list: " + list);   

//输出
zwm, item: 1
zwm, item: 2
zwm, item: 3
zwm, item: 4
zwm, item: 5
zwm, item: 1
zwm, item: 2
zwm, item: 3
zwm, item: 4
zwm, item: 5
zwm, list: [4, 5]

ListIterator是一个更加强大的Iterator的子类型,它只能用于各种List类的访问,用法如下:
(1)尽管Iterator只能向前移动,但是ListIterator可以双向移动。
(2)ListIterator可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。
(3)可以通过调用listIterator()方法产生一个指向List开始处的ListIterator,并且还可以通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。

List list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); 
ListIterator iterator = list.listIterator();
while(iterator.hasNext()) {
    Log.d(TAG, "zwm, next: " + iterator.next());
    Log.d(TAG, "zwm, nextIndex: " + iterator.nextIndex() + ", previousIndex: " + iterator.previousIndex());
}

while(iterator.hasPrevious()) {
    Log.d(TAG, "zwm, previous: " + iterator.previous());
}

iterator = list.listIterator(1);
while(iterator.hasNext()) {
    iterator.next();
    iterator.set(9);
}

Log.d(TAG, "zwm, list: " + list);   

//输出 
zwm, next: 1
zwm, nextIndex: 1, previousIndex: 0
zwm, next: 2
zwm, nextIndex: 2, previousIndex: 1
zwm, next: 3
zwm, nextIndex: 3, previousIndex: 2
zwm, next: 4
zwm, nextIndex: 4, previousIndex: 3
zwm, next: 5
zwm, nextIndex: 5, previousIndex: 4
zwm, previous: 5
zwm, previous: 4
zwm, previous: 3
zwm, previous: 2
zwm, previous: 1
zwm, list: [1, 9, 9, 9, 9]

8.Set
Set不保存重复的元素。
HashSet,使用了散列函数,数据无序。
TreeSet,将元素存储在红-黑树数据结构中,数据有序。
LinkedHashSet,使用了散列函数来提高查询速度,还使用了链表来维护元素的插入顺序。

Set set = new HashSet<>(); //无序
set.addAll(Arrays.asList(11, 55, 33, 22, 44));
Log.d(TAG, "zwm, contains: " + set.contains(33));
Log.d(TAG, "zwm, set: " + set);

set = new TreeSet<>(); //有序
set.addAll(Arrays.asList(11, 55, 33, 22, 44)); 
Log.d(TAG, "zwm, contains: " + set.contains(33));
Log.d(TAG, "zwm, set: " + set);

set = new LinkedHashSet<>(); //插入顺序
set.addAll(Arrays.asList(11, 55, 33, 22, 44)); 
Log.d(TAG, "zwm, contains: " + set.contains(33));
Log.d(TAG, "zwm, set: " + set);

//输出 
zwm, contains: true
zwm, set: [33, 22, 55, 11, 44]
zwm, contains: true
zwm, set: [11, 22, 33, 44, 55]
zwm, contains: true
zwm, set: [11, 55, 33, 22, 44]

9.Map
将对象映射到其他对象。

Map map = new HashMap<>();
map.put(11, "aa");
map.put(55, "ee");
map.put(33, "cc");
map.put(22, "bb");
map.put(44, "dd");
Log.d(TAG, "zwm, containsKey: " + map.containsKey(33));
Log.d(TAG, "zwm, containsValue: " + map.containsValue("cc"));
Log.d(TAG, "zwm, keySet: " + map.keySet());
Log.d(TAG, "zwm, values: " + map.values());
for(Integer key : map.keySet()) {
    Log.d(TAG, "zwm, key: " + key + ", value: " + map.get(key));
}
for(Map.Entry entry : map.entrySet()) {
    Log.d(TAG, "zwm, key: " + entry.getKey() + ", value: " + entry.getValue());
}

map = new TreeMap<>();
map.put(11, "aa");
map.put(55, "ee");
map.put(33, "cc");
map.put(22, "bb");
map.put(44, "dd");
Log.d(TAG, "zwm, containsKey: " + map.containsKey(33));
Log.d(TAG, "zwm, containsValue: " + map.containsValue("cc"));
Log.d(TAG, "zwm, keySet: " + map.keySet());
Log.d(TAG, "zwm, values: " + map.values());
for(Integer key : map.keySet()) {
    Log.d(TAG, "zwm, key: " + key + ", value: " + map.get(key));
}
for(Map.Entry entry : map.entrySet()) {
    Log.d(TAG, "zwm, key: " + entry.getKey() + ", value: " + entry.getValue());
}

map = new LinkedHashMap<>();
map.put(11, "aa");
map.put(55, "ee");
map.put(33, "cc");
map.put(22, "bb");
map.put(44, "dd");
Log.d(TAG, "zwm, containsKey: " + map.containsKey(33));
Log.d(TAG, "zwm, containsValue: " + map.containsValue("cc"));
Log.d(TAG, "zwm, keySet: " + map.keySet());
Log.d(TAG, "zwm, values: " + map.values());
for(Integer key : map.keySet()) {
    Log.d(TAG, "zwm, key: " + key + ", value: " + map.get(key));
}
for(Map.Entry entry : map.entrySet()) {
    Log.d(TAG, "zwm, key: " + entry.getKey() + ", value: " + entry.getValue());
}

//输出 
zwm, containsKey: true
zwm, containsValue: true
zwm, keySet: [33, 22, 55, 11, 44]
zwm, values: [cc, bb, ee, aa, dd]
zwm, key: 33, value: cc
zwm, key: 22, value: bb
zwm, key: 55, value: ee
zwm, key: 11, value: aa
zwm, key: 44, value: dd
zwm, key: 33, value: cc
zwm, key: 22, value: bb
zwm, key: 55, value: ee
zwm, key: 11, value: aa
zwm, key: 44, value: dd
zwm, containsKey: true
zwm, containsValue: true
zwm, keySet: [11, 22, 33, 44, 55]
zwm, values: [aa, bb, cc, dd, ee]
zwm, key: 11, value: aa
zwm, key: 22, value: bb
zwm, key: 33, value: cc
zwm, key: 44, value: dd
zwm, key: 55, value: ee
zwm, key: 11, value: aa
zwm, key: 22, value: bb
zwm, key: 33, value: cc
zwm, key: 44, value: dd
zwm, key: 55, value: ee
zwm, containsKey: true
zwm, containsValue: true
zwm, keySet: [11, 55, 33, 22, 44]
zwm, values: [aa, ee, cc, bb, dd]
zwm, key: 11, value: aa
zwm, key: 55, value: ee
zwm, key: 33, value: cc
zwm, key: 22, value: bb
zwm, key: 44, value: dd
zwm, key: 11, value: aa
zwm, key: 55, value: ee
zwm, key: 33, value: cc
zwm, key: 22, value: bb
zwm, key: 44, value: dd

10.Queue
队列是一个典型的先进先出的容器。
LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkdedList可以用作Queue的一种实现。

Queue queue = new LinkedList<>();
queue.offer(1);
queue.offer(5);
queue.offer(2);
queue.offer(4);
queue.offer(3);
while (!queue.isEmpty()) {
    Log.d(TAG, "zwm, poll: " + queue.poll());
}

//输出 
zwm, poll: 1
zwm, poll: 5
zwm, poll: 2
zwm, poll: 4
zwm, poll: 3

PriorityQueue,优先级队列声明下一个弹出元素是最需要的元素(具有最高优先级)。当你在PriorityQueue上调用offer()方法来插入一个对象时,这个对象会在队列中被排序。

默认的排序将使用对象在队列中的自然顺序,但是你可以通过提供自己的Comparator来修改这个顺序。PriorityQueue可以确保你调用peek()、poll()和remove方法时,获取的元素将是队列中优先级最高的元素。

PriorityQueue queue = new PriorityQueue<>(11,
        new Comparator() {
            public int compare(Integer p1, Integer p2) {
                return p1-p2;
            }
        });

for (int i = 0; i < 10; i++) {
    queue.offer(new Random().nextInt(100));
}
while (!queue.isEmpty()) {
    Log.d(TAG, "zwm, poll: " + queue.poll());
}

//输出 
zwm, poll: 0
zwm, poll: 9
zwm, poll: 39
zwm, poll: 51
zwm, poll: 66
zwm, poll: 72
zwm, poll: 73
zwm, poll: 73
zwm, poll: 75
zwm, poll: 89

11.新程序中不应该使用过时的Vector、Hashtable和Stack。

12.散列码不必是独一无二的(应该更关注生成速度,而不是唯一性),但是通过hashCode()和equals(),必须能够完全确定对象的身份。

13.hashCode()和equals()
equals():
equals()用来判断两个对象是否相等。

//Object.java
public boolean equals(Object obj) {
    return (this == obj);
}

既然Object.java定义了equals()方法,这就意味着所有的Java类都可以通过equals()方法去比较两个对象是否相等。但是,我们通常会重写equals()方法:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。

根据"类是否覆盖equals()方法",分为两个情况:
(1)若某个类无覆盖equals()方法,当它通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象,这时等价于通过"=="去比较这两个对象。

private static class Person {
    int age;
    String name;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return name + " - " + age;
    }
}

Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Log.d(TAG, "zwm, equals: " + p1.equals(p2)); //无覆写equals()方法,比较的是是否同一个对象

//输出 
zwm, equals: false

(2)若某个类有覆盖equals()方法,来让equals()通过其它方式比较两个对象是否相等。通常的做法是:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。

private static class Person {
    int age;
    String name;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return name + " - " + age;
    }

    @Override
    public boolean equals(Object obj){
        if(obj == null){
            return false;
        }

        //如果是同一个对象返回true,反之返回false
        if(this == obj){
            return true;
        }

        //判断是否类型相同
        if(this.getClass() != obj.getClass()){
            return false;
        }

        Person person = (Person)obj;
        return name.equals(person.name) && age==person.age;
    }
}

Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Log.d(TAG, "zwm, equals: " + p1.equals(p2));

//输出 
zwm, equals: true

hashCode():
hashCode()的作用是获取哈希码,也称为散列码,它实际上是返回一个int整数,这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在Object.java中,这就意味着Java中的任何类都包含有hashCode()方法。

虽然每个Java类都包含hashCode()方法,但是仅仅当创建某个类的散列表时,例如HashMap、HashSet等,该类的hashCode()方法才有用,其作用是确定该类的每一个对象在散列表中的位置。其它情况下,例如创建类的单个对象、创建类的对象数组等,类的hashCode()方法没有作用。

例子:
HashSet是Set集合,它不允许有重复元素。假设HashSet中已经有1000个元素,当插入第1001个元素时,如果将第1001个元素逐个的和前面1000个元素进行比较,显然效率是相当低下的。散列表很好地解决了这个问题,它根据元素的散列码计算出元素在散列表中的位置,然后将元素插入该位置即可,对于相同的元素,自然是只保存了一个。

由此可知,在散列表中,
(1)如果两个对象相等,那么它们的hashCode()值一定要相同;
(2)如果两个对象hashCode()相等,它们并不一定相等。

hashCode()和equals()的关系:
以"类的用途"来将hashCode()和equals()的关系分两个情况说明:
(1)不会创建"类对应的散列表"
我们不会在HashSet、HashMap等这些本质是散列表的数据结构中用到该类。例如,不会创建该类的HashSet集合。在这种情况下,该类的hashCode()和equals()没有任何关系,equals()用来比较该类的两个对象是否相等,而hashCode()则根本没有任何作用,所以不用理会hashCode()。

private static class Person {
    int age;
    String name;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return name + " - " + age;
    }

    @Override
    public boolean equals(Object obj){
        if(obj == null){
            return false;
        }

        //如果是同一个对象返回true,反之返回false
        if(this == obj){
            return true;
        }

        //判断是否类型相同
        if(this.getClass() != obj.getClass()){
            return false;
        }

        Person person = (Person)obj;
        return name.equals(person.name) && age==person.age;
    }
}

Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
Log.d(TAG, "zwm, result: " + String.format("p1.equals(p2): %s, p1( %d ), p2( %d )", p1.equals(p2), p1.hashCode(), p2.hashCode()));
Log.d(TAG, "zwm, result: " + String.format("p1.equals(p3): %s, p1( %d ), p3( %d )", p1.equals(p3), p1.hashCode(), p3.hashCode()));

//输出 
zwm, result: p1.equals(p2): true, p1( 2583521 ), p2( 78490886 )
zwm, result: p1.equals(p3): false, p1( 2583521 ), p3( 21934023 )

(2)会创建"类对应的散列表"
我们会在HashSet、HashMap等这些本质是散列表的数据结构中用到该类。例如,会创建该类的HashSet集合。在这种情况下,该类的hashCode()和equals()是有关系的:
1)如果两个对象相等,那么它们的hashCode()值一定相同。
这里的相等是指,通过equals()比较两个对象时返回true。
2)如果两个对象hashCode()相等,它们并不一定相等。
因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出键值对相等,因为有可能出现哈希冲突。

在这种情况下,若要判断两个对象是否相等,除了要覆盖equals()之外,也要覆盖hashCode(),否则equals()无效。
例如,创建Person类的HashSet集合,必须同时覆盖Person类的equals()和hashCode()方法,
如果只是覆盖equals()方法,我们会发现,equals()方法没有达到我们想要的效果。

例子:只覆盖equals()方法

private static class Person {
    int age;
    String name;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return name + " - " + age;
    }

    @Override
    public boolean equals(Object obj){
        if(obj == null){
            return false;
        }

        //如果是同一个对象返回true,反之返回false
        if(this == obj){
            return true;
        }

        //判断是否类型相同
        if(this.getClass() != obj.getClass()){
            return false;
        }

        Person person = (Person)obj;
        return name.equals(person.name) && age==person.age;
    }
}

// 新建Person对象,
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);

// 新建HashSet对象
HashSet set = new HashSet();
set.add(p1);
set.add(p2);
set.add(p3);
Log.d(TAG, "zwm, result: " + String.format("p1.equals(p2): %s, p1( %d ), p2( %d )", p1.equals(p2), p1.hashCode(), p2.hashCode()));
Log.d(TAG, "zwm, set:" + set);

//输出 
zwm, result: p1.equals(p2): true, p1( 2583521 ), p2( 78490886 )
zwm, set:[eee - 100, aaa - 200, eee - 100]

覆写的equals()方法是判断对象的内容是否相等,如果内容相等则返回对象相等。
例子中p1对象跟p2对象的内容相等,equals()方法返回true,即表示两个对象相等。既然这两个对象相等,那么HashSet中就不应该都包含这两个相等的对象,但是从打印出来的集合内容可以看到,这两个对象都被添加到HashSet中去了。这是因为虽然我们覆写的equals()方法返回了true,但是默认的Object类的hashCode()方法返回的哈希值是不同的,因此HashSet认为这不是两个相同的对象,然后把它们都添加进集合中,这就与我们最初的想法发生冲突了,因此我们还应该覆写hashCode()方法避免这个问题。

例子:同时覆盖equals()方法和hashCode()方法

private static class Person {
    int age;
    String name;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return name + " - " + age;
    }

    @Override
    public boolean equals(Object obj){
        if(obj == null){
            return false;
        }

        //如果是同一个对象返回true,反之返回false
        if(this == obj){
            return true;
        }

        //判断是否类型相同
        if(this.getClass() != obj.getClass()){
            return false;
        }

        Person person = (Person)obj;
        return name.equals(person.name) && age==person.age;
    }

    @Override
    public int hashCode(){
        int nameHash =  name.toUpperCase().hashCode();
        return nameHash ^ age;
    }
}

// 新建Person对象,
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
Person p4 = new Person("EEE", 100);

// 新建HashSet对象
HashSet set = new HashSet();
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
Log.d(TAG, "zwm, result: " + String.format("p1.equals(p2): %s, p1( %d ), p2( %d )", p1.equals(p2), p1.hashCode(), p2.hashCode()));
Log.d(TAG, "zwm, result: " + String.format("p1.equals(p4): %s, p1( %d ), p4( %d )", p1.equals(p4), p1.hashCode(), p4.hashCode()));
Log.d(TAG, "zwm, set:" + set);

//输出 
zwm, result: p1.equals(p2): true, p1( 68545 ), p2( 68545 )
zwm, result: p1.equals(p4): false, p1( 68545 ), p4( 68545 )
zwm, set:[eee - 100, EEE - 100, aaa - 200]

覆写的equals()方法是判断对象的内容是否相等,如果内容相等则返回对象相等。
覆写的hashCode()方法根据name跟age计算哈希值,如果name跟age相同则返回相同的哈希值。
当比较对象p1和对象p2时,首先比较它们的hashCode()返回值,例子中是相等的,然后再通过equals()进行比较,例子中返回true,所以对象p1和对象p2被HashSet视为相等的对象。
当比较对象p1和对象p4时,首先比较它们的hashCode()返回值,例子中是相等的,然后再通过equals()进行比较,例子中返回false,所以对象p1和对象p4被HashSet视为不相等的对象。

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

compareTo方法的返回值是int,有三种情况:
(1)比较者大于被比较者(也就是compareTo方法里面的对象),那么返回正整数;
(2)比较者等于被比较者,那么返回0;
(3)比较者小于被比较者,那么返回负整数。

例子:

public class Domain implements Comparable
{
    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;
    }
}

Domain d1 = new Domain("c");
Domain d2 = new Domain("c");
Domain d3 = new Domain("b");
Domain d4 = new Domain("d");
Log.d(TAG, "zwm, compare result: " + d1.compareTo(d2));
Log.d(TAG, "zwm, compare result: " + d1.compareTo(d3));
Log.d(TAG, "zwm, compare result: " + d1.compareTo(d4));

//输出 
zwm, compare result: 0
zwm, compare result: 1
zwm, compare result: -1

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 Domain implements Comparable
{
    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 class DomainComparator implements Comparator
{
    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;
    }
}

Domain d1 = new Domain("c");
Domain d2 = new Domain("c");
Domain d3 = new Domain("b");
Domain d4 = new Domain("d");
DomainComparator dc = new DomainComparator();
Log.d(TAG, "zwm, compare result: " + dc.compare(d1, d2));
Log.d(TAG, "zwm, compare result: " + dc.compare(d1, d3));
Log.d(TAG, "zwm, compare result: " + dc.compare(d1, d4));

//输出 
zwm, compare result: 0
zwm, compare result: 1
zwm, compare result: -1

15.优选容器而不是数组。

相关链接:

Java hashCode() 和 equals()的若干问题解答

你可能感兴趣的:(容器)