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():交换两个位置的元素