第十七章 深入理解容器

Object.hasCode()默认使用对象的地址计算散列码。

Object.equals()默认比较对象地址。

一、散列与散列码

Hash结构容器散列原理(大致的原理,没有必要较真)

 

数组保存ArrayList的引用,散列码就是数组的下标值。存储元素时计算散列码,找到元素所属List,用该对象equals()方法与List中的元素比较,若发现相等元素则覆盖,没有相等元素则在空位插入。如果散列均匀,通过散列码可以急速定位List,大大减少equals()比较操作的执行次数,提高查询速度。

二、容器

1、List

ArrayList:数组实现,随机访问更快。

LinkedList:链表实现,增删数据更快。

2、Set

Set:加入Set的元素必须实现equals()接口,以确保元素的唯一性。

HashSet:(默认选择)哈希表实现,专门对快速查找进行了优化,加入HashSet的元素必须实现hashCode()方法。

LinkedHashSet:具有HashSet的查询速度,链表维持插入顺序,元素必须实现hashCode()。

TreeSet:红黑树实现,保持元素次序,必须实现Comparable接口。

红黑树引用广泛,主要是用来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。

mport java.util.*;


class SetType {
    int i;
    public SetType(int n) {
        i =n;    
    }
    public boolean equals(Object o) {
        return o instanceof SetType && (i == ((SetType)o).i);
    } 
    public String toString() {
        return String.valueOf(i);
    }
}

class HashType extends SetType{
    public HashType(int n) {
        super(n);
    }
    public int hashCode() {
        return i%5;
    }
}

class TreeType extends SetType implements Comparable<TreeType>{
    public TreeType(int n) {
        super(n);
    }
    public int compareTo(TreeType t) {
        return (i < t.i ? -1 : ((i == t.i) ? 0 : 1));
    }
}
public class Demo1 {
    static <T> Set<T> fill(Set<T> set, Class<T> type) {
        try {
            for(int i = 0; i < 10; i++) {
                set.add(type.getConstructor(int.class).newInstance(i));
            }
        }catch(Exception e) {
            throw new RuntimeException();
        }
        return set;
    }
    static <T> void test(Set<T> set, Class<T> type) {
        fill(set,type);
        System.out.println(set);
    }
    public static void main(String[] args) {
        test(new HashSet<HashType>(), HashType.class);
        test(new TreeSet<TreeType>(), TreeType.class);
    }

}

 输出结果:

[0, 5, 1, 6, 2, 7, 3, 8, 4, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

结果分析:通过这个简单的程序了解一下原理,真正写hashCode()和equals()时的细节还是蛮多,蛮不好写的。一般来说,实现他们都是基于对象内容的。

 

3、Map

HashMap:(默认)散列表实现,查询键快。

LinkedHashMap:链表实现,迭代更快,插入(相对HashMap)稍慢,按照插入顺序或最近最少使用顺序存储元素。

TreeMap:红黑树实现,保持次序。

三、Collections类的静态方法

 1、填充容器:

import java.util.*;
class StringAddress {
    private String s;
    public StringAddress(String s) { this.s = s; }
    public String toString() {
        return super.toString() + " " + s;
    }
}
public class Demo2 {

    public static void main(String[] args) {
        List<StringAddress> l = new ArrayList<>(Collections.nCopies(2, new StringAddress("Hello")));
        l.add(new StringAddress("Hello"));
        System.out.println(l);
        Collections.fill(l, new StringAddress("World"));
        System.out.println(l);
    }

}
View Code

 输出结果:

[chapter17.StringAddress@6cd8737 Hello, chapter17.StringAddress@6cd8737 Hello, chapter17.StringAddress@22f71333 Hello]
[chapter17.StringAddress@13969fbe World, chapter17.StringAddress@13969fbe World, chapter17.StringAddress@13969fbe World]

结果分析:

nCopies():填充对象的引用,返回一个不可变数组。

fill():替换已存在的元素,且不能够添加新元素。

2、动态类型安全

import java.util.*;

class Fruit {}
class Apple extends Fruit {}
class Banana extends Fruit {}
public class CheckedList {
    @SuppressWarnings("unchecked")
    static void oldStyleMethod(List l) {
        l.add(new Banana());
    }
    public static void main(String[] args) {
        List<Apple> l1 = new ArrayList<Apple>();
        oldStyleMethod(l1);
        System.out.println(l1);
        List<Apple> l2 = Collections.checkedList(new ArrayList<Apple>(), Apple.class);
        try {
            oldStyleMethod(l2);
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

}
View Code

 输出结果:

[chapter17.Banana@1554909b]
java.lang.ClassCastException

结果分析:可以看到使用checkedList(),checkedMap(),checkedSet()进行类型的检查,可以防止老代码的偷梁换柱行为。

3、排序与查询

import java.util.*;
public class Demo3 {
    public static void main(String[] args) {
        String[] s = {"one", "two", "three", "four", "five", "Four",
                "six", "Two"};
        List<String> list = new ArrayList<String>(Arrays.asList(s));
        Collections.sort(list);
        System.out.println("sorted: " + list);
        Collections.shuffle(list);
        System.out.println("shuffle: " + list);
        Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
        System.out.println("sorted-insensitive: " + list);
        int index = Collections.binarySearch(list, "Two", String.CASE_INSENSITIVE_ORDER);
        System.out.println("Location of " + "\"Two\" is " + index);
    }
}
View Code

输出结果:

sorted: [Four, Two, five, four, one, six, three, two]
shuffle: [Two, Four, four, six, one, two, three, five]
sorted-insensitive: [five, Four, four, one, six, three, Two, two]
Location of "Two" is 6

结果说明:还是强调注意sort()与binarysearch()使用同样的Comparator。

4、设定不可修改的Collection或Map

import java.util.*;
public class Demo4 {

    public static void main(String[] args) {
        List<Integer> l1 = Arrays.asList(1,2,3,4);
        List<Integer> l2 = Collections.unmodifiableList(new ArrayList<Integer>(l1));
        System.out.println(l2);
        try {
            l2.set(0, 3);
        }catch(Exception e) {
            e.printStackTrace();
        }

    }

}
View Code

 输出结果:

[1, 2, 3, 4]
java.lang.UnsupportedOperationException

结果说明:unmodifiableList()等方法可以创建不可修改容器。

5、其他API

import java.util.*;
public class Demo5 {

    public static void main(String[] args) {
        List<Integer> l1 = new ArrayList<Integer>();
        List<Integer> l2 = new ArrayList<Integer>();
        Collections.addAll(l1, 2,3,1,4,6,8,7,5);
        Collections.addAll(l2, 8,9,10);
        System.out.println("max: " + Collections.max(l1));
        System.out.println("min: " + Collections.min(l1));
        Collections.sort(l1);
        Collections.rotate(l1, 3);
        System.out.println("rotate: " + l1);
        System.out.println("disjoint: " + Collections.disjoint(l1, l2));
        Collections.swap(l1, 0, 7);
        System.out.println("swap: " + l1);
    }

}
View Code

输出结果:

max: 8
min: 1
rotate: [6, 7, 8, 1, 2, 3, 4, 5]
disjoint: false
swap: [5, 7, 8, 1, 2, 3, 4, 6]

结果分析:这里列出了一部分方法

max():找最大

min():找最小

rotate():所有元素向后移动distance,后面元素循环到前面来

disjoint():两个集合没有相同元素返回true

swap():交换两个位置的元素

posted @ 2019-09-20 19:51  卑微芒果  Views(164)  Comments(0Edit  收藏  举报