学习笔记之《Java核心技术卷I》---- 第九章 集合

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/smart_ferry/article/details/85014447
  • ArrayDeque使用循环数组实现队(双端队列),LinkedList实现链表实现队列(也是双端队列)
  • 集合有两个基本接口:Collection、Map
  • 使用整数索引访问元素(也称随机访问)时,可以从任意位置开始访问元素;而使用迭代器访问元素时,只能从集合的第一个元素开始顺序地访问元素
  • 只有集合才需要实现Iterable接口
  • LinkedList中实现了listIterator方法,并返回一个ListIterator对象,该对象支持通过next()或previous()遍历链表元素。 但是刚开始,遍历指针是处于第一个元素之前。一开始,不能使用previous!!!并且只有当使用next或previous方法后,遍历指针才会移动!并且该对象还支持在遍历时往集合中添加元素,添加元素所在位置为遍历指针处,遍历指针原来后面的元素后移。remove方法删除上一步访问的元素,且不能连续两次调用remove方法。set方法可以用一个新元素取代调用next或previous方法返回的上一个元素。佐证代码如下:
public class Test {
	public static void main(String[] args){
		LinkedList<Integer> l = new LinkedList<>();
		l.addAll(Arrays.asList(new Integer[]{1,2,3}));
		ListIterator<Integer> iter = l.listIterator();//获得ListIterator对象,此时遍历指针处于1之前
//		System.out.println(iter.previous());//一开始不能使用previous,报错,注释后以下程序正常运行
		System.out.println(iter.next());//遍历指针前移,并返回被遍历指针所越过的元素,即1.此时遍历指针在1和2之间
		System.out.println(iter.next());//遍历指针前移,并返回被遍历指针所越过的元素,即2.此时遍历指针在2和3之间
		System.out.println(iter.previous());//遍历指针后移,并返回被遍历指针所越过的元素,即2,此时遍历指针在1和2之间
		iter.add(5);//在遍历指针处添加元素5,即在1和2之间添加元素5.其实5是被添加到了遍历指针之前的,看下一行代码的输出就知道了
		System.out.println(iter.previous());//输出为5
		iter.remove();//删除上一步访问的元素,即5
		for (Integer integer : l) {
			System.out.print(integer + " ");
		}
	}
}
  • 如果迭代器发现它的集合被另一个迭代器修改了,或是被该集合自身的方法修改了,就会抛出一个ConcurruentModificationException异常。代码佐证如下:
public class Test {
	public static void main(String[] args){
		LinkedList<Integer> l = new LinkedList<>();
		l.addAll(Arrays.asList(new Integer[]{1,2,3}));
		ListIterator<Integer> iter1 = l.listIterator();
		ListIterator<Integer> iter2 = l.listIterator();
		iter1.next();
		iter1.remove();
		iter2.next();//ConcurrentModificationException
	}
}
  • LinkedList对于get方法的优化:如果索引大于等于size / 2就从列表尾端开始搜索元素。源码:
Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
  • Java使用链表法解决哈希表中的冲突。一个桶管理一个链表
  • TreeSet使用红黑树数据结构存储元素。要使用树集,必须能够比较元素。因此这些元素必须实现Comparable接口或者提供一个Comparator
  • 优先级队列使用存储元素,其内存储的元素也必须是可比较的,因此也必须实现Comparable接口或者提供Comparator对象
  • 优先级队列每次删除的元素都是优先级数最小的那个元素(因此使用小根堆存储元素),结合小根堆的特点可知,对于堆的遍历,其元素排列未必是按自然顺序排序
  • MapObject.getOrDefault(key,defaultValue) //若该键key不存在于Map对象中,则返回默认值defaultValue
  • MapObject.put(k,v) //put方法将返回键k之前对应的值,若没有则返回null
  • Map有三种映射视图,分别为键集、值集合(不是一个集)、以及键/值对集。
Set<Integer> keys = map.keySet();
Collection<Integer> values = map.values();
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
  • keySet不是HashSet或TreeSet,而是实现了Set接口的另外某个类的对象
  • 可以在键集视图上删除元素,实际就是把对应的key的条目删除;但是不能在键集视图上增加元素。 对于值集合视图和键值对视图同样遵循此规范
public class Test {
	public static void main(String[] args){
		Map<Integer, Integer> map = new HashMap<>();
		map.put(0, 0);
		map.put(1, 1);
		map.put(2, 2);
		Set<Integer> keys = map.keySet();
		keys.remove(1);
//		keys.add(7);//报错
	}
}
  • 标识散列映射类IdentityHashMap中,键的散列值不是用hashCode函数计算的,而是用System.identityHashCode方法计算。而且,在对两个对象进行比较时,IdentityHashMap使用 “==”,而不是equals
  •  
public class Test {
	public static void main(String[] args){
		List<String> l = Collections.nCopies(5, "hello");//构建成功后,不允许对l进行任何修改
		l.forEach((s)->{System.out.println(s);});
	}
}
  • 列表子范围:subList(fromIndex,toIndex)
  •  Collections.copy(to,from)
/*
copy函数需要目的列表的size(不是capacity)大于或等于源列表的size
而size在构造列表对象时是0,只有每add成功一个元素后size才加1
*/
public class Test {
	public static void main(String[] args){
		List<Integer> l = new ArrayList<>();
		for(int i = 0;i < 10;i++) {
			l.add(i);
		}
		List<Integer> l2 = new ArrayList<>();//如果把下面的for循环注释,则会出错
		for(int i = 10;i < 20;i++) {
			l2.add(i);
		}
		Collections.copy(l2, l);
		l.forEach((x) -> {System.out.println(x);});
	}
}
  • Collections.fill(list,val)
/*
同理,使用fill函数时,也只是对list中已有的元素进行填充。与capacity无关
*/
public class Test {
	public static void main(String[] args){
		List<Integer> l = new ArrayList<>();
		for(int i = 0;i < 10;i++) {
			l.add(i);
		}
		Collections.fill(l, 100);
		l.forEach((x) -> {System.out.println(x);});
	}
}
  •  交集:retainAll
public class Test {
	public static void main(String[] args){
		Set<Integer> l = new HashSet<>();
		Set<Integer> l2 = new HashSet<>();
		l.addAll(Arrays.asList(new Integer[] {1,2,3,4}));
		l2.addAll(Arrays.asList(new Integer[] {5,3,4}));
		l.retainAll(l2);
		l.forEach((x) -> {System.out.println(x);});//3,4
	}
}
  • 差集:removeAll
public class Test {
	public static void main(String[] args){
		Set<Integer> l = new HashSet<>();
		Set<Integer> l2 = new HashSet<>();
		l.addAll(Arrays.asList(new Integer[] {1,2,3,4}));
		l2.addAll(Arrays.asList(new Integer[] {5,3,4}));
		l.removeAll(l2);
		l.forEach((x) -> {System.out.println(x);});//1,2
	}
}
  •  并集:addAll      对于Set来说是并集
public class Test {
	public static void main(String[] args){
		Set<Integer> l = new HashSet<>();
		Set<Integer> l2 = new HashSet<>();
		l.addAll(Arrays.asList(new Integer[] {1,2,3,4}));
		l2.addAll(Arrays.asList(new Integer[] {5,3,4}));
		l.addAll(l2);
		l.forEach((x) -> {System.out.println(x);});//1,2,3,4,5
	}
}
  • 将集合转成数组
public class Test {
	public static void main(String[] args){
		Set<Integer> l = new HashSet<>();
		l.addAll(Arrays.asList(new Integer[] {1,2,3,4}));
//需要提供一个所需类型而且长度为0的数组。或者如果给的数组参数的长度大于l的size,那么在返回的数组中,多余部分用null填充
		Integer[] a = l.toArray(new Integer[0]);
		for (Integer integer : a) {
			System.out.println(integer);
		}
	}
}
  •  

 

展开阅读全文

没有更多推荐了,返回首页