一、了解什么是集合框架(Collection)
集合框架的由来:数据多了用对象进行存储,对象多了用集合来进行存储,而存储数据的方式(数据结构)各有不同,所以存储的容器也就有多种,从而形成了集合框架这一体系。
在集合框架中提供了一个内部类专门操作集合中的元素,这个内部类就是迭代器。
作用:
集合可以:
1、在类的内部,对数据进行组织;
2、简单而快速的搜索大数量的条目;
3、有的集合接口,提供了一系列排列有序的元素,并且可以在序列中间快速的插入或者删除元素;
4、有的集合接口,提供了映射关系,可以通过关键字(key)快速的查找到对应的唯一对象,而这个关键字可以是任意类型。
与数组的对比:
1、数组的长度固定,集合长度可变;
2、数组只能通过下标访问元素,下标类型只能是数字型,而有的集合可以通过任意类型查找所映射的具体对象。
整个集合框架大体上可以分为三种:
线性集合类型(List 接口:ArrayList、LinkedList…) 、
集合类型(Set 接口:HashSet、TreeSet…)、
映射类型(Map 接口:HashMap、TreeMap…)。
注意:Conllection接口不是Map集合的父接口!
Collection集合框架的顶级接口UML视图:
二、Collection之List接口
我们可以看到这类(List)容器是有下标的,可以按照下标去取、删除等等方式操作容器里的元素。
list的特点:有序、对象可以重复。
list有三种遍历方式:
①迭代器Iterator
List l=new ArrayList<>();
l.add(1);
l.add(2);
l.add(3);
l.add(4);
l.add(5);
Iterator it = l.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
②foreach循环
List l=new ArrayList<>();
l.add(1);
l.add(2);
l.add(3);
l.add(4);
l.add(5);
// Iterator it = l.iterator();
// while(it.hasNext()) {
// System.out.println(it.next());
// }
for (Object obj : l) {
System.out.println(obj);
}
③通过下标循环遍历
List l=new ArrayList<>();
l.add(1);
l.add(2);
l.add(3);
l.add(4);
l.add(5);
// Iterator it = l.iterator();
// while(it.hasNext()) {
// System.out.println(it.next());
// }
// for (Object obj : l) {
// System.out.println(obj);
// }
for (int i = 0; i < l.size(); i++) {
System.out.println(l.get(i));
}
1、list集合相对于collection集合所特有的方法:
凡是可以操作角标的方法都是该体系所特有的方法。
例如:
增
Add(index,element)
Add(index,Collection)
删
Remove(index)
改
Set(index,element)
查
Get(index)
subList(from,to)
listIterator()
index(element)
2、Iterator与ListIterator的区别:
list集合所特有的迭代器,ListIterator是Iterator的子接口
在迭代时,不可以通过集合对象的方法操作集合中的元素;
因为会发生并发修改异常(ConcurrentModificationException);
所以,在迭代时,只能通过迭代器来操作元素,课时Iterator的方法是有限的,Iterator只提供了判断、取出、删除的操作;
如果想要有其他的操作,如添加、修改等,就需要使用其子接口ListIterator,该接口只能list集合的listIterator方法来获取
- listiteration还能倒着取值:
List l=new ArrayList<>();
l.add(1);
l.add(2);
l.add(3);
l.add(4);
l.add(5);
ListIterator it = l.listIterator();
while(it.hasNext()) {//正常的list迭代器 从上往下取
System.out.println(it.next());
}
while(it.hasPrevious()) {//倒着取的list迭代器 注:必须先运行正常的迭代器才能取
//因为,一开始迭代器在最上面 运行完正常的迭代器后 到达了最下面才能从下面往上取
//如果直接倒着取的话 会取不到值
System.out.println(it.previous());
}
3、集合的remove方法与迭代器的remove方法有什么区别?
①在迭代器或者foreach循环删除的时候容易出现什么常见的问题 :
②在迭代器中执行collection.remove方法
Collection c=new ArrayList<>();
c.add(1);
c.add(2);
c.add(3);
c.add(4);
c.add(5);
//在迭代器或者foreach循环删除容易出现的问题
Iterator it = c.iterator();
while(it.hasNext()) {
int num=(int)it.next();
if(num % 2 == 0) {//当num 取模2==0时 num是偶数
System.out.println(it.next());//这里打印的是num的下一个数
c.remove(num);
//当在这里进行删除时,会导致java.util.ConcurrentModificationException错误
//多方对同一个元素进行操作 导致并发问题
}
}
System.out.println(c);
// for (Object obj : c) {
// int num = (int) obj;
// if(num % 2 == 0) {
// System.out.println(obj);//这里打印的是满足条件的obj
// c.remove(obj);//当在这里进行删除时,会导致java.util.ConcurrentModificationException错误
// //多方对同一个元素进行操作 导致并发问题
//
// }
// }
List的三个子类的特点:
①Arraylist:
数组结构 增删慢,查询快 有连续下标 线程不同步 增长因子为1.5 10
② Vector:
数组结构 增删改查都慢 有连续下标 线程同步 增长因子2 10
Vector相对ArrayList查询慢(线程安全的)
Vector相对LinkedList增删慢(数组结构)
③Linkedlist:
链表结构 增删快,查询慢 没有连续下标
ArrayList 如何进行性能调优?
public class listdome2 {
public static void main(String[] args) {
ArrayList al = new ArrayList<>(80);
for (int i = 0; i < 79; i++) {
al.add(i);
System.out.println(i+"---");
getLength(al);//从这里我们可以得到arraylist底层数组的长度为多少 增长又为多少
}
//如果我们需要对arraylist进行性能调优的话,直接对底层数组的初始长度进行扩大 new ArrayList<>(80);
}
public static void getLength(ArrayList al) {
try {
Field f= al.getClass().getDeclaredField("elementData");
f.setAccessible(true);
Object obj = f.get(al);
Object [] elementData = (Object []) obj;
System.out.println("当前al容器的底层数组的长度:"+elementData.length);
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
}
- 使用LinkedList完成堆栈和队列
示意图:
- 堆栈结构(先进后出):
public class Linkedlistdemo {
public static void main(String[] args) {
Duizhan dz = new Duizhan();//堆栈
dz.push(1);
dz.push(2);
dz.push(3);
dz.push(4);
dz.push(5);
dz.bianli();
System.out.println("取前------取后");
dz.pop();
dz.bianli();
}
}
/**
* 堆栈结构的容器 特点 先进后出 最先进去的最后出来
*/
class Duizhan{
private LinkedList ll = new LinkedList<>();
/**
* 往堆栈结构里添加元素,每次放进去都是第一个
*/
public void push(Object obj) {
ll.addFirst(obj);
}
/**
* 取的同时删除堆栈里的数据 每次取都是取第一个 就形成了先进后出
*/
public Object pop() {
return ll.removeFirst();
}
/**
* 遍历
*/
public void bianli() {
Iterator it = ll.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
结果:
- 队列(先进先出):
public class Linkedlistdemo {
public static void main(String[] args) {
Duilie dz = new Duilie();//队列
dz.push(1);
dz.push(2);
dz.push(3);
dz.push(4);
dz.push(5);
dz.bianli();
System.out.println("取前------取后");
dz.pop();
dz.bianli();
}
}
/**
* 队列结构 特点:先进先出 先进去的先出来
*/
class Duilie{
private LinkedList ll = new LinkedList<>();
/**
* 往队列结构里添加元素,每次放进去都是第一个
*/
public void push(Object obj) {
ll.addFirst(obj);
}
/**
* 取的同时删除队列里的数据 每次取都是取最后一个 就形成了先进先出
*/
public Object pop() {
return ll.removeLast();
}
/**
* 遍历
*/
public void bianli() {
Iterator it = ll.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
结果:
集合框架ArrayList中的重复元素去重及其底层原理:
①字符串去重:
public class ArrayListdemo3 {
public static void main(String[] args) {
ArrayList al = new ArrayList<>();
al.add("q");
al.add("w");
al.add("e");
al.add("r");
al.add("t");
al.add("t");
ArrayList newal=al;//建立新的容器容纳
System.out.println("去重前容器大小:"+newal.size());
newal=repeat(al);
System.out.println("去重后容器大小:"+newal.size());
}
/**
* arraylist 如何去重
* 1.建立一个新的容器
* 2.将老的容器遍历取出其中的元素
* 3.如果说这个元素存在于新容器中,那么不再往新容器加入。如果不存在,就加
*
* @param al
* @return
*/
public static ArrayList repeat(ArrayList al) {
ArrayList newal = new ArrayList<>();//建立新容器
for (Object obj : al) {//循环
if(!newal.contains(obj)) {//循环判断是否重复 newal.contains(obj)
//如果不重复就往新容器里添加
newal.add(obj);
}
}
return newal;
}
}
结果:
②自定义对象去重
public class ArrayListdemo3 {
public static void main(String[] args) {
ArrayList al = new ArrayList<>();
// al.add("q");
// al.add("w");
// al.add("e");
// al.add("r");
// al.add("t");
// al.add("t");
al.add(new Person("q", 1));
al.add(new Person("w", 2));
al.add(new Person("e", 3));
al.add(new Person("r", 4));
al.add(new Person("t", 5));
al.add(new Person("q", 1));
al.add(new Person("w", 2));
ArrayList newal=al;//建立新的容器容纳
System.out.println("去重前容器大小:"+newal.size());
newal=repeat(al);
System.out.println("去重后容器大小:"+newal.size());
}
/**
* arraylist 如何去重
* 1.建立一个新的容器
* 2.将老的容器遍历取出其中的元素
* 3.如果说这个元素存在于新容器中,那么不再往新容器加入。如果不存在,就加
*
* @param al
* @return
*/
public static ArrayList repeat(ArrayList al) {
ArrayList newal = new ArrayList<>();//建立新容器
for (Object obj : al) {//循环
if(!newal.contains(obj)) {//循环判断是否重复 newal.contains(obj)
//如果不重复就往新容器里添加
newal.add(obj);
}
}
return newal;
}
}
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
/**
* 重写equals方法
*/
@Override
public boolean equals(Object obj) {
Person p = (Person) obj;
// System.out.println(p.name+"---equals---"+this.name);
return p.name.equals(this.name) && p.age == this.age;
}
}
结果: