- Collection接口,单列集合,用来存储一个一个的对象
- List接口,存储有序、可重复的数据(动态数组)
- ArrayList
- LinkedList:
- Vector:
- Set接口,存储无序、不可重复的元素
- HashSet
- LinkedHashSet
- TreeSet
Collection接口常用方法
- boolean add(E e):添加元素
-
boolean addAll(Collection c):将指定 collection 中的所有元素都添加到此 collection 中
-
void clear():移除此 collection 中的所有元素(可选操作)。
-
int size():获取集合长度(元素个数)
-
boolean isEmpty():判断集合是否为空
-
boolean contains(Object obj):判断集合是否有指定的obj元素,会自动调用对象的equals()方法进行比较,会从容器的第一个元素开始比较,直到存在比较相同的原始,或查找到容器的结尾
-
containsAll(Collection coll):判断参数容器内的元素是否都在此容器中,
注意:此方法也会表用元素对象类中的equals()方法,不分元素的顺序,只要全部包含即可
-
remove():移除指定的元素,同样会调用equals()方法进行比较判断是否相同,仅移除第一次出现此元素的元素
-
removeAll(Collection c):从集合中移除参数集合中所有元素(只能移除共有的部分)
-
retainAll(Collection c):仅保留指定集合中共有的元素
-
equals(Object obj):比较此 collection 与指定对象是否相等,比较的是元素
-
hashCode():返回hash值
-
toArray():将集合转为数组
-
Iterator iterator():返回在此 collection 的元素上进行迭代的迭代器
Iterator迭代器
Iterator迭代器主要用来遍历Collection容器的,不包括Map
遍历集合
Iterator iterator = coll.iterator();
next():下一个元素,每次调用后指向下一个元素
hasNext():判断是否还有更多的元素
使用迭代器遍历集合与删除元素
@Test
public void test1() {
Collection coll = new ArrayList();
coll.add(11);
coll.add(22);
coll.add(33);
coll.add(44);
//返回此元素的迭代器
Iterator iterator = coll.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
@Test
public void test2() {
Collection coll = new ArrayList();
coll.add(11);
coll.add(22);
coll.add(33);
coll.add("Tom");
//iterator.remove():从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)
// 每次调用 next 只能调用一次此方法
Iterator iterator = coll.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
if("Tom".equals(next)) {
iterator.remove();
}
System.out.println(next);
}
System.out.println("—————");
iterator = coll.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
List
List实现类与区别
- ArrayList
- 作为List接口的主要实现类,线程不安全的,效率高,底层使用Object[]存储插入是将后面的元素都往后移动一位,删除是将后面的元素都往前移动,增删效率底,查找效率高如果知道存储的长度,推荐实例化的时候就指定长度
**LinkedList** * 底层使用双向链表存储,内存是连续的,对应频繁的插入和移除操作,此类效率比ArrayList高,查找效率低
**Vector** * 作为List接口的古老实现类,线程安全的,效率底
List接口新增方法
List接口中,在Collection接口基础上,主要增加了一些带索引的方法
void add(int index, E element):在此列表中的指定位置插入指定的元素
boolean addAll(int index, Collection c):将指定集合中的所有元素插入到此列表中,从指定的位置开始。
E get(int index):返回此列表中指定位置的元素
int indexOf(Object o):返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1
int lastIndexOf(Object o):返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1
E remove(int index):删除该列表中指定位置的元素
E set(int index, E element):用指定的元素替换此列表中指定位置的元素
List subList(int fromIndex, int toIndex):返回此列表中指定的 fromIndex (包括)和 toIndex之间的子集合
ArrayList
作为List接口的主要实现类,线程不安全的,效率高,底层使用Object[]存储插入是将后面的元素都往后移动一位,删除是将后面的元素都往前移动,增删效率底,查找效率高如果知道存储的长度,推荐实例化的时候就指定长度
遍历
iterator() 迭代器遍历
增强for循环 forEach
普通for循环
注意
在add()方法中,参数是Object类型,所以如果存储的是基本数据类型,会自动装箱,在remove()方法中,有重载的方法,如果写remove(2),就是删除索引为2的元素,因为重载的方法有参数为int类型的,如果要删除值为2的元素,要使用包装类装箱new Integer(2)或 Integer.valueOf(2);
要求
作为List接口的子类容器,存储的对象要重写equals()方法,因为有remove()、contains()等方法需要使用到
示例
@Test
public void test() {
ArrayList<Integer> list = new ArrayList<>(10);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List<Integer> list1 = Arrays.asList(3, 4, 5, 6);
//addAll(int index, Collection c):将指定集合中的所有元素插入到此列表中,从指定的位置开始
list.addAll(2,list1);
System.out.println("addAll "+list);
//add(int index, E element):在此列表中的指定位置插入指定的元素
list.add(1,8);
System.out.println("add "+list);
//indexOf(Object o):返回此列表中指定元素的第一次出现的索引
//lastIndexOf(Object o):返回此列表中指定元素的最后一次出现的索引
System.out.println("indexOf "+list.indexOf(3));
System.out.println("lastIndexOf "+list.lastIndexOf(3));
//remove(int index):删除该列表中指定位置的元素
list.remove(1);
System.out.println("remove "+list);
//get(int index):返回此列表中指定位置的元素
System.out.println("get "+list.get(1));
//set(int index, E element):用指定的元素替换此列表中指定位置的元素
list.set(2,Integer.valueOf(9));
System.out.println("set "+list);
List<Integer> subList = list.subList(2, 6);
System.out.println("subList "+subList);
}
LinkedList
使用同ArrayList,底层使用的是双向链表,增删效率高,查询效率低
要求
作为List接口的子类容器,存储的对象要重写equals()方法,因为有remove()、contains()等方法需要使用到
Vector
作为List接口的古老实现类,线程安全的,效率底
使用同ArrayList,底层使用的是数组,线程安全,一般都使用ArrayList
要求
作为List接口的子类容器,存储的对象要重写equals()方法,因为有remove()、contains()等方法需要使用到
Set
Set特点
Set接口容器存放的元素具有 无序性、不可重复性
Set实现类与区别
- HashSet:Set接口的主要实现类,线程不安全的,可以存储null值,底层是HashMap
- LinkedHashSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历对于频繁的遍历,LinkedHashSet效率高于HashSet
**TreeSet**:底层是红黑树存储的,存储的必须是同一个类的对象。可以按照添加的对象按照指定的属性进行排序
新增方法
Ste接口中没有新增的方法,因为Ste是无序的,不需要索引,使用的都是Collection中声明的方法
HashSet
无序性、不可重复性
Set接口的主要实现类,线程不安全的,可以存储null值,底层是HashMap
理解
在HashSet中理解无序性、不可重复性
无序性
不等于随机性;有序性,像数组,存放数据时是一个挨着一个的,而实现Set接口的容器,存放数据时是无序的,存储的位置并非按照添加的顺序添加的,是按照hashCode值决定元素在数组中存储的位置。
不可重复性
当元素的hashCode不同时,必定是不同的元素,存储在不同的位置,当hashCode相同时那么存储的位置也是同一个地方,发现此位置已经有了元素,那么就比较equals(),如果是相同的,新元素存储失败,如果比较不同,则在此位置使用链表的方式存储;
添加元素存储的过程(以HashSet为例)
add()元素,hashCode决定存储位置
此位置是否有元素,如果无元素,存储成功,如果此位置有元素,比较equals(),如果equals()不同,则使用链表的方式在此位置存储元素,如果equals()相同,认为是同一个元素存储失败其实此过程都是底层HashMap完成的
jdk7:新的元素在数组中,指向原来的元素
jdk8:原来的元素放在数组中,指向新的元素
要求
HashSet和LinkedHashSet容器中的元素必须重写hashCode()和equals()
实例
//HashSet
@Test
public void test1() {
HashSet set = new HashSet();
set.add(456);
set.add(123);
set.add("AA");
set.add("CC");
set.add(789);
Iterator iterator = set.iterator();
//遍历的数据顺序与添加的顺序不同 AA CC 789 456 123
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
LinkedHashSet
作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历对于频繁的遍历,LinkedHashSet效率高于HashSet
要求
HashSet和LinkedHashSet容器中的元素必须重写hashCode()和equals()
使用方法于HashSet一致
TreeSet
底层是红黑树存储的,可以按照添加的对象按照指定的属性自动调用元素的比较器进行排序
注意
- 存储的必须是同一个类的对象
- 存储的对象,其类要实现Comparable接口比较器
- 在TreeSet中,存储元素的时候会先调用对象的比较器中的比较方法进行比较和排序,如果比较方法比较两个对象返回的是0,就认为是同一个对象,添加失败
- 自然比较排序:调用compareTo()方法进行比较排序,而不再是equals()
- 定制比较排序:调用compare()方法,而不再是equals(),在new实例化的时候就需要传入Comparator比较器对象
要求
TreeSet容器中存储的元素必须实现Comparable比较器接口,重写compareTo()
示例
//添加的元素自定义类实现Comparable接口,添加数据时,内部使用Comparable进行自然排序
@Test
public void test2() {
TreeSet set = new TreeSet();
//添加的对象必须是同一个类的对象
set.add(new Person("Tom",16));
set.add(new Person("Jerry",18));
set.add(new Person("Jim",19));
set.add(new Person("Timi",24));
set.add(new Person("Timi",25));
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
//自定义类实现Comparator接口,添加数据时,内部使用Comparator进行定制排序
//使用定制排序需要再new实例化对象的时候传入Comparator实例对象
@Test
public void test3() {
Comparator<Person> comparator = new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
//仅按照年龄升序排序
return o1.getAge() - o2.getAge();
}
};
TreeSet set = new TreeSet(comparator);
//添加的对象必须是同一个类的对象
set.add(new Person("Tom",16));
set.add(new Person("Jerry",18));
set.add(new Person("Jim",19));
set.add(new Person("Timi",24));
set.add(new Person("Timi",25));
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
//自定义的Person类,重写了compareTo()方法部分
@Override
public int compareTo(Person o) {
//按照姓名从小到大排序,如果姓名一样再按照年龄
// 直接调用String类中的compareTo()方法
int flag = this.name.compareTo(o.name);
if(flag != 0) {
return flag;
} else {
flag = this.age - o.age;
return flag;
}
}