前言:
这一章先不讲各个集合底层的一些原理,先将Collection这个对象存在哪些方法都尝试一遍。
Collection
public static void main(String[] args) {
Collection<Integer> collection = new ArrayList<>(16);
collection.add(1);
Collections.addAll(collection, 2,3,4,5,6);
// 函数式编程的遍历,后面会说到函数式编程
collection.forEach((a)->System.out.print(a));// 123456
collection.remove(2);// 删除元素
System.out.println(collection.contains(2));// false 是否包含2这个元素
System.out.println(collection.isEmpty());// false 是否为空
System.out.println(collection.size());// 5 元素的数量
// 返回一个数组,没有在括号中传入指定的类型,返回的是Object类型的数组
System.out.println(collection.toArray());// [Ljava.lang.Object;@20c684
System.out.println();
// 迭代器遍历,增强for循环的内部也是个iterator迭代器
Iterator<Integer> it = collection.iterator();
while (it.hasNext()) {
System.out.print(it.next());// 13456
}
}
这个里面别的没什么好说的,主要就是在用迭代器遍历元素时,不能用集合删除一个元素,还是使用上面的集合。
while (it.hasNext()) {
if (it.next()== 4) {
// collection.remove(4); // ConcurrentModificationException
it.remove();
}
}
应该使用迭代器的remove方法,为什么会报错呢?我debug了一下,主要就是modCount != expectedModCount
实际修改的计数器和预期修改的计数器不相等(每修改一次,计数器就会加一),至于为什么计算器不相等呢?小伙伴们可以去网上在搜一搜,我看了半天也没发现哪里悄悄更改了二者的值,反正一开始是相等的,奈何本人初学能力有限见谅,源码在这里
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
泛型
定义:可以在类或方法中预支地使用未知的类型。
好处:
- 将运行期间的异常提升到了编译期间,这个很好理解,我定义一个集合,然后不指定其泛型,也就是说什么引用类型都可以往里面放(其实他们都被提升为了Object类型),然后取出来的时候进行类型转换(假设都转为String),就会发现类型转换异常,如果你只是要打印输出一下,那不转也没事,我的意思是如果你想将这些元素遍历然后由于某一需要,进行类型转换时,你不可能保证所有的都能正常转为String,那时候就报错,而泛型由于在编程时就将该集合的类型早早确定下来了,后续你不可能往里面加的了不是String的数据的,会编译报错的。
- 避免了类型强转的麻烦。一开始都定义好了类型,还要什么后续强转呢。
- 如果不指定集合以什么类型存储元素,则默认都以Object类型存储,这就带来了一个严重的问题,用Object元素来表示元素类型没有问题,但每次进行一些操作都要拆箱、装箱,占用了大量的计算机资源,导致程序性能低下。而使用泛型则在编译阶段就告诉编译器,数据结构中元素的种类,既然编译器知道了元素的种类,自然就避免了重复的拆箱、装箱的操作,从而显著提高程序的性能。
泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素的自身方法无法使用。
通配符高级使用----泛型受限
Collection<Integer> list1 = new ArrayList<>();
Collection<String> list2 = new ArrayList<>();
Collection<Number> list3 = new ArrayList<>();
Collection<Object> list4 = new ArrayList<>();
getElement(Collection<? extends Number> coll){}// 这是上限
getElement2(Collection<? super Number> coll){}// 这是下限
getElement(list1);// 编译正确
getElement(list3);// 编译正确
getElement(list2);// 编译错误
getElement(list4);// 编译错误
getElement2(list3);// 编译正确
getElement2(list4);// 编译正确
getElement2(list1);// 编译错误
getElement2(list2);// 编译错误
所谓上限是指括号中接收的类的类型最多是Number类型或者Number子类。
所谓下限是指括号中接收的类的类型至少是Number类型或者Number父类。
这个估计用的也不多,了解了解就可以了。