容器(集合框架)
为什么使用集合框架?
Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中
面向接口编程
1、接口
2、具体类
3、算法
Collection接口的常用方法
集合作为容器应该具有的功能(增,删,改,查),
不一定全有。
集合的基本操作:增加,删除,判断,取出
List与Set接口
Map接口存储一组键值对象,提供key到value的映射
List接口的实现类:
List特点:有序,不唯一(可重复)
ArrayList实现了长度可变的数组,在内存中分配连续的空间。
优点:遍历元素和随机访问元素的效率比较高
缺点:添加和删除需要大量移动元素效率低,按照内容查询效率低
LinkedList采用链表存储方式。
优点:插入、删除元素时效率比较高
缺点:遍历和随机访问元素效率低下
List接口特有的方法:
注意:获取List长度用size()方法
List<String> list = new ArrayList<>();//<String>规定只能装String类型
list.add("java");
list.add("html");
list.add("css");
list.add("java");
System.out.println(list);
ArrayList
ArrayList的增删查改
实现了List接口,ArrayList中允许存在Null元素,此实现不是同步的(效率高)
Vector(线程安全,效率低)
list接口继承Collection 继承 Iterable
以及容器中所有元素的遍历
调用list.add的时候才有初始容量,刚new的时候size是0
构造方法:
ArrayList()
构造一个初始容量为 10 的空列表。
ArrayList(Collection< ? extends E> c)
构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
ArrayList(int initialCapacity)
构造一个具有指定初始容量的空列表。
成员方法:
boolean add(E e)
将指定的元素添加到此列表的尾部。
void add(int index, E element)
将指定的元素插入此列表中的指定位置。
boolean addAll(Collection< ? extends E> c)
按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。
boolean addAll(int index, Collection< ? extends E> c)
从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。
void clear()
移除此列表中的所有元素。
Object clone()
返回此 ArrayList 实例的浅表副本。
boolean contains(Object o)
如果此列表中包含指定的元素,则返回 true。
void ensureCapacity(int minCapacity)
如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。
E get(int index)
返回此列表中指定位置上的元素。
int indexOf(Object o)
返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
boolean isEmpty()
如果此列表中没有元素,则返回 true
int lastIndexOf(Object o)
返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。
E remove(int index)
移除此列表中指定位置上的元素。
boolean remove(Object o)
移除此列表中首次出现的指定元素(如果存在)。
protected void removeRange(int fromIndex, int toIndex)
移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。
E set(int index, E element)
用指定的元素替代此列表中指定位置上的元素。
int size()
返回此列表中的元素数。
Object[] toArray()
按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。
void trimToSize()
将此 ArrayList 实例的容量调整为列表的当前大小。
测试代码:
public class Test1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
/* Collection<String> collection = new ArrayList<>();
Iterable<String> iterable = new ArrayList<>();*/
//增加元素 add() insert()
list.add("one");
list.add(1, "two");
list.add(list.size(),"three");
//将自身所有的元素在加一遍
list.addAll(list);
System.out.println(list);
//查询元素
System.out.println("是否包含one:"+list.contains("one"));
System.out.println("one的索引值:"+list.indexOf("one"));
System.out.println("最后一个one的索引值:"+list.lastIndexOf("one"));
//修改元素
list.set(3, "four");
System.out.println(list);
//删除元素 remove delete
list.remove(0);//删除索引值为0的元素
list.remove("two");//删除容器中第一个与目标元素相同的元素
System.out.println(list);
//打印第一个元素
System.out.println("第一个元素:"+list.get(0));
//容器的遍历方式
showArrayList(list);
}
/**
* 展示容器内所有元素
* @param list
*/
public static void showArrayList(List<String> list) {
//1.for循环
/*for(int i = 0;i < list.size();i++){
System.out.println(list.get(i));
}
//2.for-each
for (String string : list) {
System.out.println(string);
}*/
//3.迭代器 Iterator
//获取指向容器首个元素迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
Vector
Vector:
- 底层为对象数组
- Object[]data
- 可以实现可增长的对象数组
- Vector 是同步的 (jdk1.0)
-
- 构造方法:
- 默认初始容量为10
-
- 成员方法:
- 增加
- add(E e)
- add(int index,E e)
- addAll()
- addAll(int index,Colleaction< ? extends E> collection)
- void insertElementAt(E obj, int index)
将指定对象作为此向量中的组件插入到指定的 index 处 - 删除
E remove(int index)
移除此向量中指定位置的元素。
boolean remove(Object o)
移除此向量中指定元素的第一个匹配项,如果向量不包含该元素,则元素保持不变。
boolean removeAll(Collection< ?> c)
从此向量中移除包含在指定 Collection 中的所有元素。
void removeAllElements()
从此向量中移除全部组件,并将其大小设置为零。
boolean removeElement(Object obj)
从此向量中移除变量的第一个(索引最小的)匹配项。
void removeElementAt(int index)
删除指定索引处的组件。
protected void removeRange(int fromIndex, int toIndex)
从此 List 中移除其索引位于 fromIndex(包括)与 toIndex(不包括)之间的所有元素
clear();修改
E set(int index, E element)
用指定的元素替换此向量中指定位置处的元素。
void setElementAt(E obj, int index)
将此向量指定 index 处的组件设置为指定的对象。查询
- contains()
- indexOf()
- lastIndexOf()
- 遍历
- 1.for循环
- 2.for-each
- 3.迭代器
测试代码:
public class TestVector {
public static void main(String[] args) {
Vector<String> vector = new Vector<>();
vector.add("one");
vector.insertElementAt("zero", 0);
vector.addElement("two");
System.out.println(vector);
//
/*vector.removeElementAt(0);
System.out.println(vector);
vector.remove(0);
System.out.println(vector);
vector.remove("two");
System.out.println(vector);
vector.removeAllElements();
vector.clear();*/
//修改
vector.set(0, "零");
vector.setElementAt("壹", 1);
System.out.println(vector);
//是否包含零
System.out.println("是否包含零:"+vector.contains("零"));
System.out.println("零的索引值:"+vector.indexOf("零"));
showVector(vector);
}
/**
* 展示容器vector中所有的元素
* @param vector
*/
public static void showVector(Vector<String> vector){
//1.for循环
for (int i = 0; i < vector.size(); i++) {
//根据索引值获取元素
System.out.println(vector.get(i));
//vector特有的方法
System.out.println(vector.elementAt(i));
}
//2.for-each
for (String string : vector) {
System.out.println(string);
}
//3.迭代器
//a.获取指向容器的迭代器
Iterator<String> iterator = vector.iterator();
//Iterator<String> iterator1 = vector.listIterator();
//b.让迭代器迭代,知道没有下一个元素为止
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
泛型
为什么需要泛型
解决数据类型操作不统一产生的异常
使用泛型可以更好的去保护数据类型
用处:
1.接口定义的时候
public interface<E>{
}
2.类定义的时候
public class Student<K,V>{
public void show(K key1,V value1){
}
}
3.方法的定义中(前提类中已经定义了该泛型)
public void show(K key1,V value1){
}
4.上界控制
<? extends Student>
5.下界控制
<? super Student>
测试代码:
public class Test2 {
public static void main(String[] args) {
/*List<SuperClass> list = new ArrayList<>();
showList(list);
List<Object> list2 = new ArrayList<>();
//这种写法报错,上界控制的时候,只能放SuperClass或者是SuperClass的子类
showList(list2);
*/
//下界控制
List<SuperClass> list3 = new ArrayList<>();
showList1(list3);
List<Object> list4 = new ArrayList<>();
showList1(list4);
List<SubClass> list5 = new ArrayList<>();
//这种写法报错,下界控制的时候,只能放SuperClass或者是SuperClass的父类
//showList1(list5);
}
public static void showList(List<? extends SuperClass> list){
}
//下界控制
public static void showList1(List<? super SuperClass> list){
}
}
父类:
public class SuperClass {
}
子类:
public class SubClass extends SuperClass{
}
模拟系统类实现List的面向接口编程
自定义接口:
public interface MyList <E>{
int size();
void add(E e);
E get(int index);
void set(int index,E e);
}
子类实现接口:
public class MyArrayList<E> implements MyList<E>{
private Object[]elementData;
private int size;
public MyArrayList() {
this(10);
}
public MyArrayList(int initSize) {
if(initSize < 0) throw new IllegalArgumentException("非法参数");
elementData = new Object[initSize];
}
@Override
public void add(E e) {
elementData[size++] = e;
}
@SuppressWarnings("unchecked")
@Override
public E get(int index) {
if(index < 0 || index >= size) throw new IllegalArgumentException("非法参数");
return (E) elementData[index];
}
@Override
public void set(int index, E e) {
if(index < 0 || index >= size) throw new IllegalArgumentException("非法参数");
elementData[index] = e;
}
@Override
public int size() {
return this.size;
}
}
测试代码:
public class Test1 {
public static void main(String[] args) {
//接口指向实现类
MyList<String> list = new MyArrayList<>(10);
list.add("zero");
list.add("one");
list.set(0, "two");
showMyArrayList(list);
}
/**
* 展示自定义容器中所有的方法
* @param list
*/
public static void showMyArrayList(MyList<String>list) {
for(int i = 0;i < list.size();i++){
System.out.println(list.get(i));
}
}
}
LinkedList
LinkedList
链表
除了实现List接口之外,Deque(队列接口)
元素有序,不唯一;允许NUll元素,此实现不是同步的。
构造方法:
LinkedList()
构造一个空列表。
成员方法:
增
add()
addFirst()
addLast()
offer()
offerFirst()
offerLast()
push(E e)
删
E remove()
获取并移除此列表的头(第一个元素)。
E remove(int index)
移除此列表中指定位置处的元素。
boolean remove(Object o)
从此列表中移除首次出现的指定元素(如果存在)。
E removeFirst()
移除并返回此列表的第一个元素
E removeLast()
移除并返回此列表的最后一个元素
E poll()
获取并移除此列表的头(第一个元素)
E pollFirst()
获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
E pollLast()
获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
E pop()
从此列表所表示的堆栈处弹出一个元素。
查
contains();
indexOf();
改
E set(int index, E element)
将此列表中指定位置的元素替换为指定的元素。
迭代:
Iterator descendingIterator()
返回以逆向顺序在此双端队列的元素上进行迭代的迭代器。
ListIterator listIterator(int index)
返回此列表中的元素的列表迭代器(按适当顺序),从列表中指定位置开始。
测试代码:
public class TestLinkedList {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
// Queue<String> queue = new LinkedList<>();
// Deque<String> deque = new LinkedList<>();
list.add("one");
list.add("two");
list.add("three");
list.set(0, "一");
System.out.println(list);
//根据值删除
/*if(list.contains("一")){
list.remove("一");
}*/
//根据索引值删除
int index = list.indexOf("一");
if(index >= 0){
list.remove(index);
}
showLinkedList(list);
}
/**
* 遍历LinkedList中的所有元素
* @param lkList
*/
public static void showLinkedList(List<String>lkList) {
//1.for循环
for(int i = 0;i < lkList.size();i++){
System.out.println(lkList.get(i));
}
//2.for-each
for (String string : lkList) {
System.out.println(string);
}
//3.迭代器
Iterator<String> iterator = lkList.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
Iterator
所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象。
Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。
Iterator接口定义了如下方法:
boolean hasNext(); //判断是否有元素没有被遍历
Object next(); //返回游标当前位置的元素并将游标移动到下一个位置
void remove(); //删除游标左面的元素,在执行完next之后该
//操作只能执行一次
所有的集合类均未提供相应的遍历方法,而是把遍历交给迭代器完成。迭代器为集合而生,专门实现集合遍历
Iterator是迭代器设计模式的具体实现
Iterator方法
boolean hasNext():判断是否存在另一个可访问的元素
Object next():返回要访问的下一个元素
void remove():删除上次访问返回的对象
可以使用Iterator遍历的本质是什么?
实现Iterable接口
为什么不使用for增强;
For-each循环
增强的for循环,遍历array或Collection的时候相当简便
无需获得集合和数组的长度,无需使用索引访问元素,无需循环条件
遍历集合时底层调用Iterator完成操作
For-each缺陷
数组:
不能方便的访问下标值
不要在for-each中尝试对变量赋值,只是一个临时变量
集合:
与使用Iterator相比,不能方便 的删除集合中的内容
For-each总结
除了简单的遍历并读出其中的内容外,不建议使用增强for
使用迭代器例子:
arrayList:
//3.迭代器 Iterator
//获取指向容器首个元素迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
为什么需要ListIterator
在迭代过程中,准备添加或者删除元素
ArrayList al=new ArrayList();
al.add("java1");//添加元素
al.add("java2");
al.add("java3");
//遍历
Iterator it=al.iterator();
while(it.hasNext()){
Object obj=it.next();
if (obj.equals("java2")) {
al.add("java9");
}
sop("obj="+obj);
}
ListIterator的作用->解决并发操作异常
在迭代时,不可能通过集合对象的方法(al.add(?))操作集合中的元素,
会发生并发修改异常。
所以,在迭代时只能通过迭代器的方法操作元素,但是Iterator的方法
是有限的,只能进行判断(hasNext),取出(next),删除(remove)的操作,
如果想要在迭代的过程中进行向集合中添加,修改元素等就需要使用
ListIterator接口中的方法
ListIterator li=al.listIterator();
while(li.hasNext()){
Object obj=li.next();
if ("java2".equals(obj)) {
li.add("java9994");
li.set("java002");
}
}
sop(al);
判断前边是否有元素
小结
ArrayList
遍历元素和随机访问元素的效率比较高
插入、删除等操作频繁时性能低下
Vector
LinkedList
插入、删除元素时效率较高
查找效率较低
迭代器
泛型
遍历arrayList和linkedList的三种方式