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()计算出对象的存储位置,来取代对键的缓慢搜索。