集合框架的概念
数组问题:
- 连续的,添加删除麻烦
- 数组长度是固定的,无法扩展
- 数组只能存储一种类型的数据
集合用来存储一组对象。
- 集合的长度是可以扩展的(自动扩展)
- 集合可以存储不同类型的数据(只能存储引用数据类型)
(基本类型会先转为包装类然后转成Object类型) - 操作非常方便,性能更强
集合框架的继承体系
Collection单列接口
-
List子接口:有序的,可以重复
1、实现类ArrayList:底层实现是可变数组,是Object数组,查询速度块,增删慢
2、实现类LinkedList:底层实现是双向链表,查询速度慢,增/删/改速度快
3、实现类Vector:底层实现和ArrayList一样,但效率低,在线程安全中使用。 -
Set子接口:无序的,不重复
1、实现类HashSet:底层实现是基于哈希算法,无序的,存取速度快
Map双列接口:通过键(key)值(value)对来存储数据。键不允许重复,值可以重复
- 实现类HashMap:底层实现是基于哈希算法,键可以是Null值,值可以是Null,值可以重复(键不能有两个空值,否则就重复了)
- 实现类HashTable:底层是基于哈希算法,键和值都不能是NULL。效率低
Collection接口
单列集合的根接口,提供了很多方法:
- 新增元素
boolean add(E e)
boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合
- 删除元素
boolean remove(Object o)
boolean removeAll(Collection<?> c)
void clear()
- 判断元素
- 遍历元素
- 其他
int size() 返回此集合中的元素数。
List接口
1、有序可重复的。(有序指的是add的顺序和遍历的顺序是一致的)
2、继承了collection接口
3、实现类都支持下标,从0开始
常用的方法
- 添加
void add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
List list=new ArrayList();
list.add("123");
list.add(1,"456");//在指定位置放
System.out.println(list);
E get(int index) 返回此列表中指定位置的元素。
List list=new ArrayList();
list.add("123");
list.add(1,"456");//在指定位置放
System.out.println(list);
//返回具体的数据类型
String s=(String)list.get(0);//因为add将元素转为object,然后返回之前的类型就需要向下转型
System.out.println(s);
- 查找
int indexOf(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
- 删除
E remove(int index) 删除该列表中指定位置的元素(可选操作)。
boolean remove(Object o) 从列表中删除指定元素的第一个出现(如果存在)
String s=(String)list.get(0);//因为add将元素转为object,然后返回之前的类型就需要向下转型
System.out.println(s);
list.remove("123");
System.out.println(list);
list.remove(Integer.valueOf(456));//按元素删除需写入object类型数据,及将元素换为包装类
System.out.println(list);
list.remove(list.get(0));
//由于在插入元素的时候已经被转为object类型,所以可以用get获取元素。同时也可以直接输入索引删除
System.out.println(list);
5.替换 E set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。
- ArrayList的常用方法基本上都是继承自Collection接口和List接口
- ArrayList原理
- 实现类LinkedList
底层实现是双向链表,在集合中元素会保存前一个元素和后一个元素的地址值,通过双向操作来实现
增删快,查询慢
重头开始慢慢找。
查询的时候,LinkedList必须从链条开始的位置查找,所以效率低。
增删的时候,LinkedList直接添加链条的节点/或者删除节点就行了,效率高。 - 独有的方法
增加
void addFirst(E e)
在该列表开头插入指定的元素。
void addLast(E e)
将指定的元素追加到此列表的末尾。
LinkedList list=new LinkedList();
list.add("abc");
list.addFirst("123");
list.addLast("abc");
System.out.println(list);
删除
E removeFirst()
从此列表中删除并返回第一个元素。
E removeLast()
从此列表中删除并返回最后一个元素。
获取
E get(int index)
返回此列表中指定位置的元素。
E getFirst()
返回此列表中的第一个元素。
E getLast()
返回此列表中的最后一个元素。
package com.m.demo2;
import java.util.Iterator;
import java.util.LinkedList;
public class Test {
public static void main(String[] args) {
LinkedList list=new LinkedList();
Emp emp1=new Emp("abc",11);
Emp emp2=new Emp("ab",12);
Emp emp3=new Emp("a",13);
list.add(emp2);
list.addFirst(emp3);
list.addLast(emp1);
// System.out.println(list);
Iterator iter=list.iterator();
while(iter.hasNext()) {
Emp e=(Emp)iter.next();
System.out.println(e.name+" "+e.age);
// System.out.println(iter.next());
}
// Iterator iter2=list.iterator();
list.removeFirst();
list.removeLast();
iter=list.iterator();
// System.out.println(list);
while(iter.hasNext()) {
Emp e=(Emp)iter.next();
System.out.println(e.name+" "+e.age);
// System.out.println(iter.next());
}
}
}
集合遍历
- 使用普通for循环遍历
// 方法一
for(int i=0;i<list.size();i++) {
// list.get(i);
System.out.println(list.get(i));
}
- 使用增强版for循环
for(Object o:list) {
System.out.println(o);
}
- 使用迭代器
Iterator<E> iterator() 返回此集合中的元素的迭代器。
boolean hasNext()
如果迭代具有更多元素,则返回 true 。
E next()
返回迭代中的下一个元素。
default void remove()
从底层集合中删除此迭代器返回的最后一个元素(可选操作)。
Iterator iterator= list.iterator();//迭代器对象
while(iterator.hasNext()) {
System.out.println(iterator.next());
// iterator.next();
}
1、迭代器是通用的遍历方式
2、迭代效率较高
3、迭代一次后,如果想重新再迭代一次,需要重新引用迭代器
在集合存储对象
LinkedList list=new LinkedList();
Emp emp1=new Emp("abc",11);
Emp emp2=new Emp("ab",12);
Emp emp3=new Emp("a",13);
list.add(emp2);
list.addFirst(emp3);
list.addLast(emp1);
System.out.println(list.contains(emp1));
- 在集合中可以放任何引用元素
- contains底层是使用equals方法,但是集合并没有重写equals方法,所以比较的时候,使用的Object的equals,比较的是地址值。
- 如果要比较内容,就必须重写equals方法!!!
并发修改异常
集合泛型
解决类型太多,向下转型复杂的问题.(集合中定义类型后,添加的类型是必须一致的 )
集合<数据类型> 变量名=new 集合<>();
List<Student> list=new ArrayList<>();
int sum=0;
Scanner s=new Scanner(System.in);
for (int i=0;i<5;i++) {
System.out.println("输入学生名字和成绩");
list.add(new Student(s.next(),s.nextInt()));
}
for(Student stu:list) {
sum+=stu.getGrade();
System.out.println(stu.getName()+" "+stu.getGrade());
}
System.out.println("平均分:"+(sum/5));
- 类上的泛型
定义:具有1个或者多个泛型变量的类叫做泛型类。这个泛型的变量可以是成员变量,也可以是方法的参数或者返回值。
public class 类名<T>{
private T t;
public List<T> 方法名(T t){
return null;
}
}
- 方法上定义泛型
只有在返回值前面有的,才能叫做泛型方法
//有返回值的
public<T> T 方法名(){
return null;
}
//无返回值
public<T> void T() 方法名{
}
- 接口上定义泛型
public interface 接口名<T,E>{
//参数泛型
public void 方法名(T t);
//返回值泛型
public List<E> 方法名();
}
- 迭代器使用泛型
List<Student> list=new ArrayList<>();
int sum=0;
Scanner s=new Scanner(System.in);
for (int i=0;i<5;i++) {
System.out.println("输入学生名字和成绩");
list.add(new Student(s.next(),s.nextInt()));
}
Iterator<Student> iterator = list.iterator();
while(iterator.hasNext()) {
Student stu = iterator.next();
System.out.println(stu );
}