Arrays、Collections
1 )数组集合之间转换
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
a)Arrays.asList()这个方法是用传入的数组作为底层实现的,因此不能不改变大小,即“固定尺寸”
b)注意这里返回的ArrayList 是Arrays的内部类
c)因为不能改变大小,所以并没实现增删方法,涉及到这些操作,会抛出异常
UnsupportedOperationException;表示不支持请求的操作
List<String> list =Arrays.asList("数组");
//不能这样操作
list.add("java.lang.UnsupportedOperationException");
d)因为修改没有违反“尺寸固定”,所以可以通过set(int index, E element)对List元素进行修改,当然也
会关联的修改数组
e) 所以在将数组转成集合时,应把ArrayList.asList()的结果作为构造器的参数传递给任何的
Collection(或者使用addAll()方法,或Collections.addAll()静态方法),
可以这样处理:
//方法1
List<String> list = new ArrayList<String>(Arrays.asList("数组"));
//方法2
List<String> list = new ArrayList<String>();
list.addAll(Arrays.asList("数组"));
//方法3
Collections.addAll(list, "数组");
f)将集合转换成数组,Set同样适用
List<String> list = new ArrayList<String>(Arrays.asList("数组"));
//默认返回的Object数组
Object[] obj1 = list.toArray();
//不能用强制类型转换,运行时报错
//String[] str1 = (String[]) list.toArray();
//可以传入一个空的数组,目的告诉toArray要转换的类型
String[] str2 = list.toArray(new String[0]);
//直接传入一个等大小的数组进去
String[] str3 = new String[list.size()];
list.toArray(str3);
2 )Collections可利用现有容器生成不可修改容器
//传入任何Collection子类,返回一个不可修改Collection对象
public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c)
//传入ArrayList、LinkedList ,返回不可修改的List
public static <T> List<T> unmodifiableList(List<? extends T> list)
//传入HashSet ,返回不可修改Set
public static <T> Set<T> unmodifiableSet(Set<? extends T> s)
//传入TreeSet ,返回不可修改SortedSet
public static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T> s)
//传入HashMap ,返回不可修改Map
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m)
//传入TreeMap ,返回不可修改SortedMap
public static <K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K, ? extends V> m)
a)返回一个只读集合,这样别人只能看到,不能修改内容
b)可通过原引用对集合进行修改
b)上面都是Collections中方法
c)返回的不可修改容器,通过将原容器包装(装饰者模式),将每个涉及到修改容器的方法都返回
UnsupportedOperationException
d) 看一个实例代码
List<String> list = new ArrayList<String>(Arrays.asList("数组"));
List<String> unmodif = Collections.unmodifiableList(list);
unmodif.add("java.lang.UnsupportedOperationException");
3)Collections可利用现有容器生成同步容器
//传入任何Collection子类,返回一个同步Collection对象
public static <T> Collection<T> SynchronizedCollection(Collection<? extends T> c)
//传入ArrayList、LinkedList ,返回同步的List
public static <T> List<T> SynchronizedList(List<? extends T> list)
//传入HashSet ,返回同步Set
public static <T> Set<T> SynchronizedSet(Set<? extends T> s)
//传入TreeSet ,返回同步SortedSet
public static <T> SortedSet<T> SynchronizedSortedSet(SortedSet<T> s)
//传入HashMap ,返回同步Map
public static <K,V> Map<K,V> SynchronizedMap(Map<? extends K, ? extends V> m)
//传入TreeMap ,返回同步SortedMap
public static <K,V> SortedMap<K,V> SynchronizedSortedMap(SortedMap<K, ? extends V> m)
a)返回的同步容器,通过将原容器包装(装饰者模式),新对象每个方法前加上Synchronized关键字。
b)方法可以有第二个参数,自己设置锁对象
4)Collections可利用现有容器生成检查容器
//传入任何Collection子类,返回一个检查Collection对象
public static <E> Collection<E> checkedCollection(Collection<E> c,Class<E> type)
//传入ArrayList、LinkedList ,返回检查的List
public static <E> List<E> checkedList(List<E> list, Class<E> type)
//传入HashSet ,返回检查Set
public static <E> Set<E> checkedSet(Set<E> s, Class<E> type)
//传入TreeSet ,返回检查SortedSet
public static <E> SortedSet<E> checkedSortedSet(SortedSet<E> s,Class<E> type)
//传入HashMap ,返回检查Map
public static <K, V> Map<K, V> checkedMap(Map<K, V> m,Class<K> keyType,alueType)
//传入TreeMap ,返回检查SortedMap
public static <K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K, V> m,Class<K> keyType,Class<V> valueType)
a)返回的检查容器,通过将原容器包装(装饰者模式),在对象新增等时,对传入的对象进行类型检查
b)第二参数就是传入参数必须要满足的类型
c)功能出现的原因:可能将错类型带到泛型集合中。
List<String> list = new ArrayList<String>(Arrays.asList("数组"));
List obj = list;
obj.add(new Date());//list中存在了一个非String类型,程序执行到这里不会报错
d)解决方案
List<String> list = new ArrayList<String>(Arrays.asList("数组"));
List<String> safeList = Collections.checkedList(list, String.class);
List obj = safeList;
//检查容器视图受限于虚拟机可运行的运行时检查
obj.add(new Date());//只有执行到这一步才会抛出java.lang.ClassCastException
5)Collections、Arrays排序
//Collections只对List排序
public static <T extends Comparable<? super T>> void sort(List<T> list)
public static <T> void sort(List<T> list, Comparator<? super T> c)
a)上面是Collections中方法,可对ArrayList、LinkedList 进行排序。默认升序排列
c) 降序可在第二个参数中传入Collections.reverseOrder()
b)排序过程:先将List生成一个数组,通过Arrays.sort()对数组进行排序。然后将数组重新写入
集合List中。
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
c)Arrays.sort()可以对各种类型数组进行排序,当然对象要先实现Comparable接口。也可将
Comparator作为参数传入
d)用上面方法对List排好序后,可用Collections.binarySearch()方法进行二分查找
e)看个栗子
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>(Arrays.asList(3, 2, 5, 6,
1, 4));
System.err.println(list);// [3, 2, 5, 6, 1, 4]
// 升序
Collections.sort(list);
System.err.println(list);// [1, 2, 3, 4, 5, 6]
// 降序
Collections.sort(list, Collections.reverseOrder());
System.err.println(list);// [6, 5, 4, 3, 2, 1]
// 自己写的排序条件
Comparator<Integer> compare = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2; // 升序
}
};
// 升序
Collections.sort(list, compare);
System.err.println(list);// [1, 2, 3, 4, 5, 6]
// 二分查找
int i = Collections.binarySearch(list, 5);
System.err.println(i); // 4
}
使用Abstract类
a) java.util容器都有自己的抽象类,他们提供了该容器的部分实现,如果想创建定制的Collection
和Map实现,可以继承抽象类,实现那些产生想要的容器所必须的方法。
b)创建一个只读的Map,可以继承AbstractMap并实现entrySet(),其返回一个Entry的set集合
c)创建一个只读的set,可以继承AbstractSet并实现iterator()和size()。
d)以上的put都会抛出UnsupportedOperationException,表示不支持的请求操作。remove都是通过
set的迭代器实现的,设计时可讲remove也抛出上面异常
e) 通过AbstractList创建一个只读的List,必须实现get()和size()。其他add、set、reomove都会抛出上
面异常。
compareTo() 和 equals()
a)当重写equals并实现Comparable接口时,要保证一致的自然顺序。
b)如果equals()对于某个特定的值产生true,那么compareTo()对于该比较应该返回0
c)如果equals()对于某个特定的值产生false,那么compareTo()对于该比较应该返回非0
hashCode散列码
a)hashCode() 只有在这个类会被置于散列集合HashSet,LinkedHashSet,HashMap,linkedHashMap
(Map中放在key位置)才是必须的。
b)要想使hashCode() 实用,哈希算法必须速度快,并且必须有意义,也就是说,他必须基于对象的
内容生成的散列码(相同内容对象,生成的hashcode相同)。
c)对象散列码意义,容器会通过对象散列码,计算出其在容器中的位置,进行快速查找。
d)散列码不必须是独一无二的(不同内容的对象可以生成相同的散列码,但是好的hashCode() 应该
产生分布均匀的散列码),应该更关注生成速度,而不是唯一性,但是通过hashCode() 和equals(),
必须能够完全确定对象身份
e)根据散列集合的数据结构,首先用对象的散列码算出对象在容器中的位置,如果两个对象计算出相
同的存储位置,就通过equals()比较是否相等。
f )如果不覆盖hashCode()和equals(),那么使用散列结构就无法正确处理你的键。
g)对于良好的编程风格而言,应该在覆盖equals()方法时,总是同时覆盖hashCode()方法。
h)重写时要遵循一定的规则比如,hashCode()相等equals()不一定返回true,hashCode()不相等
equals()一定返回false,equals()返回ture那么hashCode()一定相等,,,,,,,,
i)默认的Object.hashCode()是跟据对象所在内存地址计算出的一串数字,都不相等。
默认的Object.equals()比较的是内存地址。所以对象用在Hash集合中时都需要重写。
j)Hash集合就是使用对象的hashCode()计算出对象的存储位置,来取代对键的缓慢搜索。