欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java集合辅助类 Collections、Arrays 博客分类: java集合 ArraysCollectionsHashCode 

程序员文章站 2024-02-25 18:18:15
...

 

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