1. 集合 Collection 单列集合
集合就是一种容器,不同的容器有不同特点;
特点:
1. 集合长度可变 【扩容机制】
2. 集合只能存引用数据类型
- Collection 没有带索引的方法
- List 1.有序(存取有序)2.有索引3.可重复
- ArrayList 数组(jdk1.2产物)
- LinkedList 链表
- Vector 数组(jdk1.0已被ArrayList取代)
- Set 1.无序(存取无序)2.无索引3.不可重复
- HashSet 哈希表(数组+链表+红黑树) 特点:去重
- LinkedHashSet
- TreeSet 红黑树 特点:查询快,排序
常用方法:
Collection<E>
boolean add(E e); 向集合中添加元素
void clear(); 清空集合元素
boolean contains(E e); 判断是否包含指定元素
boolean isEmpty(); 判断集合是否为空
boolean remove(E e); 判断是否删除指定元素
Object[] toArray(); 将集合转成数组 Object[] arr = {1,true,"abc"};
T[] toArray(T[] arr); 将集合转为指定类型的数组
Student[] arr = c.toArray(new Student[0]);
//参数数组的长度:如果长度大于集合的元素个数,那么集合填充数组前面的位置
//如果数组长度小于集合个数,那么数组长度为集合的长度
2. 迭代器
iterator
就是一种遍历的方式;
每个不同的集合,都有它自己的内部迭代器;
创建迭代器对象:
Iterator<E> it = list.iterator();
常用方法:
boolean hasNext(); 判断是否有下一个元素
E next(); 取出元素
void remove(); 删除元素
注意事项:
1. 不能在使用迭代器遍历集合的同时,去通过集合对象,操作集合的元素个数;(并发修改异常) modCount++;
2. 只能通过迭代器自己的方法去删除或者增加元素;iterator.remove() listIterator.add()/remove()
3. 在使用迭代器拿元素的时候,it.next()只需要调用一次即可,不能调用两次;
NoSuchElementsException:找不到元素异常
ConcurrentModificationException:并发修改异常
产生的原因:
在使用迭代器遍历集合的同时,操作原集合的个数;
解决方案:
别这么干!
使用迭代器自己的方法,对集合进行操作;
如果是删除元素,可以使用Iterator自己的remove()方法;
如果是添加元素,可以使用ListIterator自己的remove()方法;
3. 增强for
foreach就是一个使用了迭代器的普通for循环,但是我们还看不到迭代器;
增强for循环,只能遍历集合,不能做其它任何操作;
格式:
for(容器的数据类型 变量 : 容器(集合/数组)){
变量; //就是集合或数组中的每一个元素
}
注意事项:
// 遍历思路1 将集合转换成数组 遍历数组 【如果需求是将元素转换成大写】
Object[] objects = coll.toArray();//得到的是Object对象 其没有toUpperCase方法
for (Object object : objects) {
String string = (String) object;
System.out.println(string.toUpperCase());
}
// 改进方案
// new String[0]这个时候会自动给你分配有个coll.size 大小的数组
//或者new String[coll.size()]
String[] strings = coll.toArray(new String[0]);
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i].toUpperCase());
}
4. 泛型
就是一种容器上的【标签】;
只在编译期有效;
好点:
1. 把运行时期的异常,提前到了编译期;
2. 避免的类型的强转;
自定义泛型:
类:
class A<W>{
public void show(W s){
System.out.println(s);
}
}
使用:创建对象的时候,确定类的泛型
A<String> a = new A<>();
a.show("123");
class A<S,W>{
public void show(S s){
System.out.println(s);
}
public void add(W w){
}
}
使用:
A<String,Integer> a = new A<>();
a.show("123");
接口:
interface Inter<A>{
void show(A a);
A getSomething();
}
// 实现类确定接口泛型
class InterImpl implements Inter<String>{
@Override
public void show(String s) {
}
@Override
public String getSomething() {
return null;
}
}
// 实现类也不确定接口泛型,所以实现类和接口泛型保持一致
// 在创建实现类对象时,确定泛型
class InterImpl<E> implements Inter<E>{
@Override
public void show(E s) {
}
@Override
public E getSomething() {
return null;
}
} InterImpl<String> s = new InterImpl<>();
// 类有类的泛型,接口的泛型依旧不确定,所以类只能定义两个泛型
class InterImpl<E,W> implements Inter<E>{
@Override
public void show(E s) {
}
@Override
public E getSomething() {
return null;
}
public void method(W w){
}
}
InterImpl<String,Integer> i = new InterImpl<>();
方法:
public static <T> T method(){
T t = new T();
return t;
}
使用:在调用方法的时候,确定方法泛型的类型
泛型通配符:【了解】
通配符通常使用在方法的参数位置;
相当于告诉调用者,这个方法限定是什么,以及限定了什么;
<?>
? : 无边界通配符,不能添加数据,也不能获取数据,只能通过增强for遍历
? extends C : 限定你能传入的上限类型 C 我们只能传C及其C的子类 ? extends Animal
? super C : 限定你能传入的下限类型 C 我们只能传C及其C的父类 ? super Animal Object
上界类型通配符:add方法受限
下界类型通配符:get方法受限
如果你想从一个数据结构里获取数据,使用 ? extends 通配符
如果你想把对象写入一个数据结构里,使用 ? super 通配符
如果你既List想存,又想取,那就别用通配符