java集合框架
java集合框架
前言:本节我们来学习java集合框架
1.0 什么是集合
集合便是对象的容器,定义了多个对象进行操作的常用方法
集合和数组的区别:
1 数组长度固定,集合长度不固定
2 数组可以存储基本类型和引用类型,集合只能存储引用类型。
我们在使用集合时,需要导入java.utill的所有内容
1.1 Collection体系集合
collection是该体系的根节点,它的子节点由List和Set
List接口的特点:有序,有下标,元素可重复,有序,即存储顺序就是元素插入到list中的顺序,
且可以根据下标来根据顺序进行访问。
Set接口的特点:无序,无下标,元素不能重复。
上面的这三者是接口,规定了要实现的内容,具体的内容必须由接口的子类来实现,所以上面这
三者是无法实例化的。我们来看一下正Collection体系的图:
1.2 Collection父接口
该接口的方法:
1. 添加功能
boolean add(E e)
添加一个元素
boolean addAll(Collection c)
添加一批元素
2. 删除功能
boolean remove(Object o)
删除一个元素
3. 判断功能
boolean contains(Object o)
判断集合是否包含指定的元素
boolean isEmpty()
判断集合是否为空(集合中没有元素)
4. 获取功能
int size()
获取集合的长度
5. 转换功能
Object[] toArray()
把集合转换为数组
还有其他方法请查看api
需要注意的是,collection是接口,我们无法直接实例化,可以借助指向其子类的对象来实例
化,此时我们称其为实现类这就体现了java的多态特点,比如我们可以指向ArrayList,由于下
标是在其实现类中实现的,所以不能直接使用下标进行访问,如果我们利用类型转化将其转化
为ArrayList,就可以使用下标对其进行访问,由之前多态的学习我们可以知道,对于在子类中
被重载的方法,如果我们用父类执行子类的对象,那么这些方法可以在父类中使用,对于接口
也是这样。
对于集合的遍历,我们可以使用增强for,也可以使用迭代器,java中提供了迭代器接口,由不同
的类进行了实现。迭代器接口定义了三个方法 hasNext()
Next()
remove()
第一个方法是判断集合中是否存在下一个元素,第二个方法是将引用转向下一个元素,第三个
方法是用于迭代器中的对集合中元素进行删除的方法。
import java.util.*;
import com.corejava.test.*;
public class Main {
public static void main(String[] args) {
Collection collection = new ArrayList<>();
collection.add("1");
collection.add("2");
System.out.println(collection.size());
collection.remove("1");
collection.add("dada");
System.out.println(collection);
// 增强for
for (Object o : collection) {
System.out.println(o);
}
// 迭代器
Iterator i = collection.iterator();
while (i.hasNext()) {
System.out.println(i.next());
i.remove();
}
}
}
i.remove()
是删除迭代器当前指向的函数。不能直接使用collection.re
move(i)
我们还需要注意的是,当我们使用增强类对集合进行遍历时,对于上面的o的类型只能是
object,不能是集合中存储数据的类型, 如果我们想要使用集合中比如对象的方法,需要使用到
强制类型转化
举个列子
import java.util.*;
import com.corejava.test.*;
public class Main {
public static void main(String[] args) {
var s1 = new Dog("john");
var s2 = new Dog("jack");
Collection c = new ArrayList();
c.add(s1);
c.add(s2);
for (Object i : c) {
Dog d = (Dog) i;
d.makeSound();
}
}
}
还需要记住,无论是添加还是删除,直接操作的都是引用对应的地址,我们删除并非是将该元素
从地址中删除,而是删除引用对该地址的指向, 实际还是会在存储空间中存储该元素,因此我
们知道,在使用删除方法时并不是按值进行删除的,而是按地址进行删除的,我们如果删除一个
和集合中某元素的值相同,但地址不同的对象,实际上并不会删除。
1.3 List接口
List接口是Collection接口的子接口,特点有:
有序,有下标,元素可以重复
常见方法:
indexOf()
返回此列表中第一次出现的指定元素的索引,如果不包含,则返回-1
add(int index, Object o)
通过此方法,我们可以在对应下标处添加元素。
add(int index,Collection c )
将一个集合中的元素添加到此集合中的index位置
Object get(int index)
返回指定位置的元素
List subList(int fromIndex,int toIndex)
返回两个位置之间的元素,以List形式返回。
两个这个区间任然为左闭右开
除了这些方法,其父接口Collection的所有方法它也具有,可以使用
下面是一个实际使用 subListd的例子
import java.util.*;
import com.corejava.test.*;
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 1; i <= 4; i++) {
list.add(i);
}
List a = list.subList(1, 3);
for (Object object : a) {
System.out.println(object);
}
}
}
我们如果想要根据下标访问对应的元素,需要用到get(int intdex)
方法。还需要注意的是,
如果我们按下标添加,必须要根据顺序从下标0从小到大进行添加,如果我们想要对某个下标的
值进行更改,不能超出当前最大下标,原因是list接口的实现类ArrayList是动态内存,是根据我
们目前的使用去不断扩大内存的,所以我们如果索引指向没有扩大的下标是无法进行插入和访问
的,还需要注意的是,当我们使用add(Object o)
时,是将元素加到最后,当我们add(int
index,Object o)
时,是将当前坐标以及后面的所有的元素往后移一格,然后再将插入的元
素插入对应坐标
import java.util.*;
import com.corejava.test.*;
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
list.add(0, 1);
System.out.println(list.get(0));
}
}
remove(int index)
根据脚标删除元素
remove(Object o)
根据值删除元素,删除第一次出现的元素
我们需要注意的是,当list的元素全是数字类型时,我们使用remove(Object o)
是不行的,因
为此时o为数字,会默认将其认为是下标,而不是具体的值。为什么会这样呢?因为集合是不能
添加基本类型的,而数字正是基本类型,当我们将数字加入集合时有一个自动装箱过程,将其转
化为包装类 我们来看一下其解释:
自动装箱(autoboxing)是Java5中引入的一项功能,它指的是Java编译器会自动将基本数据类
型值转换为对应的包装器类型对象的过程。例如,将int类型的变量转换为Integer对象,将
boolean类型的变量转换为Boolean对象。
那我们此时如果想要根据数字的值来进行删除,应该怎么做呢?既然基本类型在存储是会自动装
箱,将其转换为对象,那我们直接将数字转化为对象再删除即可。
import java.util.*;
import com.corejava.test.*;
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 0; i <= 3; i++) {
list.add(i, i);
}
list.add(3, 11);
// list.remove(11); 这种方式不行
list.remove((Object) 11);
//list.remove((Integer) 11); 这种也可以
//list.remove(new Integer(11)); 这种也可以
for (Object object : list) {
System.out.println(object);
}
}
}
换成字符串就正常了。
List的遍历方式有很多,for ,增强for ,迭代器 迭代器除了上面的普通迭代器,还有列表迭代
器
for利用的是get方法访问角标,增强for和迭代器访问和Collection相同
import java.util.*;
import com.corejava.test.*;
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 0; i <= 3; i++) {
list.add(i, i);
}
Iterator it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
我们再来看看系列表迭代器 如何使用
该迭代器的功能要多于普通的迭代器,它允许我们选择向前或者向后遍历,允许我们添加,删
除,修改元素
常用方法(忽略了与普通迭代器相同的部分):
nextIndex()
返回下一个元素的角标
hasPreviouse()
与hasNext()
类似,只不过是判断上一个元素是否存在
previousIndex()
返回上一个元素的角标
previous()
将引用指向上一个元素,返回的值是泛型类型E的值, E代表List中存储的元素类
型 即原本存什么值便返回什么值。
set()
将某位置的元素进行替换
add()
我们已知在使用普通迭代器时,是不能增加元素的,但对于系列表迭代器的add方法则是
可以加入元素的。
import java.util.*;
import com.corejava.test.*;
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
for (int i = 0; i <= 3; i++) {
list.add(i, i);
}
ListIterator it = list.listIterator();
while (it.hasNext()) {
System.out.println(it.nextIndex() + ":" + it.next());
}
System.out.println("-------------------");
while (it.hasPrevious()) {
System.out.println(it.previousIndex() + ":" + it.previous());
}
}
}
1.4 List实现类
ArryList
由数组结构实现,查询块,增删慢。
JDK1.2版本,运行效率快,线程不安全
Vector
由数组结构实现,查询块,增删慢。
JDK1.0版本,运行效率慢,线程安全
LinkedList
链表结构实现,增删快,查询慢。