集合
集合是JAVA中为我们提供的一种“容器”,可以存储东西。
集合概述
1.1、什么是集合?有什么用?
数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。
集合为什么说在开发中使用较多?
集合是一个容器,是一个载体,可以一次容纳多个对象。
在实际开发中,假设连接数据库,数据库当中有10条记录,
那么假设把这10条记录查询出来,在java程序中会将10条
数据封装成10个java对象,然后将10个java对象放到某一个
集合当中,将集合传到前端,然后遍历集合,将一个数据一个
数据展现出来。
1.2、集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,
集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)
list.add(100); //自动装箱Integer
注意:
集合在java中本身是一个容器,是一个对象。
集合中任何时候存储的都是“引用”。
1.3、在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中
存储元素,等于将数据放到了不同的数据结构当中。
什么是数据结构?数据存储的结构就是数据结构。不同的数据结构,数据存储方式不同。
例如:
数组、二叉树、链表、哈希表...
以上这些都是常见的数据结构。
new ArrayList(); 创建一个集合,底层是数组。
new LinkedList(); 创建一个集合对象,底层是链表。
new TreeSet(); 创建一个集合对象,底层是二叉树。
1.4、集合在java JDK中哪个包下?
java.util.*;
所有的集合类和集合接口都在java.util包下。
1.5、在java中集合分为两大类:
一类是单个方式存储元素:
单个方式存储元素,这一类集合中超级父接口:java.util.Collection;
一类是以键值对(kay and value)的方式存储元素
以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;
集合继承图(重点!)
集合拥有着一大系列的关系,下面的图为我们展现了常用集合的关系
要知道的是,并非仅仅只有图中的集合,只列出了常用的集合类型。
具体查询API即可。
要很熟悉该图,知道哪些是接口,哪些是类。
Collection
Collection是一部分集合的父类接口,也就是说在Collection中的方法
都能在其子类中去找到并完成实现。所以非常重要,这涉及到集合的操作。
Collection接口中常用方法
关于java.util.Collection接口中常用的方法。
1、Collection中能存放什么元素?
没有使用“泛型”之前,Collection中可以存储Object的所有子类型。
使用了“泛型”之后,Collection中只能存储某个具体的类型。
集合后期我们会学习“泛型”语法。目前先不用管。Collection中什么都能存,
只要是Object的子类型就行。(集合中不能直接存储基本数据类型,也不能存
java对象,只是存储java对象的内存地址。)
2、Collection中的常用方法
boolean add(Object e) 向集合中添加元素
int size() 获取集合中元素的个数
void clear() 清空集合
boolean contains(Object o) 判断当前集合中是否包含元素o,包含返回true,不包含返回false
boolean remove(Object o) 删除集合中的某个元素。
boolean isEmpty() 判断该集合中元素的个数是否为0
Object[] toArray() 调用这个方法可以把集合转换成数组。【作为了解,使用不多。】
具体的代码试验如下:
public static void main(String[] args) {
创建一个集合对象
错误!Collection c = new Collection();
接口是抽象的,无法实例化。
应该用多态
Collection c = new ArrayList();
测试Collection接口中的常用方法
c.add(1200);
为什么能直接写1200?因为自动装箱(java5的新特性。)
实际上是放进去了一个对象的内存地址。
类似于
Integer x = new Integer(1200);
c.add(x);
c.add(3.14); // 自动装箱
c.add(new Object());
c.add(new Student());
c.add(true); // 自动装箱
获取集合中元素的个数
System.out.println("集合中元素个数是:" + c.size()); // 5
清空集合
c.clear();
System.out.println("集合中元素个数是:" + c.size()); // 0
再向集合中添加元素
c.add("hello"); // "hello"对象的内存地址放到了集合当中。
c.add("world");
c.add("浩克");
c.add("绿巨人");
c.add(1);
判断集合中是否包含"绿巨人"
boolean flag = c.contains("绿巨人");
System.out.println(flag); // true
boolean flag2 = c.contains("绿巨人2");
System.out.println(flag2); // false
System.out.println(c.contains(1)); // true
System.out.println("集合中元素个数是:" + c.size()); // 5
删除集合中某个元素
c.remove(1);
System.out.println("集合中元素个数是:" + c.size()); // 4
判断集合是否为空(集合中是否存在元素)
System.out.println(c.isEmpty());
false
清空
c.clear();
System.out.println(c.isEmpty());
true(true表示集合中没有元素了!)
转换成数组(了解,使用不多。)
Object[] objs = c.toArray();
for(int i = 0; i < objs.length; i++){
遍历数组
Object o = objs[i];
System.out.println(o);
}
}
深入Collection集合的contains方法
boolean contains(Object o)
判断集合中是否包含某个对象o
如果包含返回true, 如果不包含返回false。
contains方法是用来判断集合中是否包含某个元素的方法,
那么它在底层是怎么判断集合中是否包含某个元素的呢?
调用了equals方法进行比对。
equals方法返回true,就表示包含这个元素。
public static void main(String[] args) {
创建集合对象
Collection c = new ArrayList();
向集合中存储元素
String s1 = new String("abc"); // s1 = 0x1111
c.add(s1); // 放进去了一个"abc"
String s2 = new String("def"); // s2 = 0x2222
c.add(s2);
集合中元素的个数
System.out.println("元素的个数是:" + c.size()); // 2
新建的对象String但是不存入集合中
String x = new String("abc"); // x = 0x5555
c集合中是否包含x?结果猜测一下是true还是false?
System.out.println(c.contains(x));
}
一般来说,c和x是两个引用,他们存储的内存地址是不一样的。
但是由于contains方法底层其实调用了equals方法,所以会在此时调用。
而c和x是两个String类型的引用,equals被重写了,所以c和x在equals方法下是相等的!
所以c.contains(x)是true!
深入Collection集合的remove方法
boolean remove(Object o) 删除集合中的某个元素。
其实他的底层也调用了equals方法去判断。
通过类的equals方法去比对传的参数o和集合中的元素是否相等,从而判断是否要删除。
public static void main(String[] args){
创建集合对象
Collection cc = new ArrayList();
创建字符串对象
String s1 = new String("hello");
加进去。
cc.add(s1);
创建了一个新的字符串对象
String s2 = new String("hello");
删除s2
cc.remove(s2);
s1.equals(s2) java认为s1和s2是一样的。删除s2就是删除s1。
集合中元素个数是?
System.out.println(cc.size()); // 0
}
结论
存放在一个集合中的类型,一定要重写equals方法!!!
集合遍历/迭代(重点!)
首先我们可以在API中发现,Collection接口其实还继承了一个接口:
Iterable
这个接口提供了一个方法
iterator()
返回类型为 Iterator 迭代器。
下面通过实例来了解迭代器
注意:以下讲解的遍历方式/迭代方式,是所有Collection通用的一种方式。
在Map集合中不能用。在所有的Collection以及子类中使用。
public static void main(String[] args) {
创建集合对象
后面的集合无所谓,主要是看前面的Collection接口,怎么遍历/迭代。
Collection c = new ArrayList();
添加元素
c.add("abc");
c.add("def");
c.add(100);
c.add(new Object());
对集合Collection进行遍历/迭代
第一步:获取集合对象的迭代器对象Iterator
Iterator it = c.iterator();
第二步:通过以上获取的迭代器对象开始迭代/遍历集合。
以下两个方法是迭代器对象Iterator中的方法:
boolean hasNext()如果仍有元素可以迭代,则返回 true。
Object next() 返回迭代的下一个元素。
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
}
abc
def
100
java.lang.Object@10f87f48
前面我们提到
List集合存储元素特点:有序可重复
Set集合存储元素特点:无序不可重复。
下面通过迭代器来对其进行探究
public static void main(String[] args) {
创建集合对象
Collection c1 = new ArrayList(); // ArrayList集合:有序可重复
添加元素
c1.add(1);
c1.add(2);
c1.add(3);
c1.add(4);
c1.add(1);
迭代集合
Iterator it = c1.iterator();
while(it.hasNext()){
存进去是什么类型,取出来还是什么类型。
Object obj = it.next();
只不过在输出的时候会转换成字符串。因为这里println会调用toString()方法。
System.out.println(obj);
}
HashSet集合:无序不可重复
Collection c2 = new HashSet();
无序:存进去和取出的顺序不一定相同。
不可重复:存储100,不能再存储100.
c2.add(100);
c2.add(200);
c2.add(300);
c2.add(90);
c2.add(400);
c2.add(50);
c2.add(60);
c2.add(100);
Iterator it2 = c2.iterator();
while(it2.hasNext()){
System.out.println(it2.next());
}
}
通过观察输出我们可以发现
对于List集合,存进去是什么顺序,迭代输出也是什么顺序。
而对于Set集合,存入的顺序无法决定输出的顺序,每次输出的顺序是无序,乱的
而且对于重复的元素,只会输出一次,说明重复的元素无法存入。
关于迭代器的更新
一定要注意:集合结构只要发生改变,迭代器必须重新获取。
当集合结构发生了改变,迭代器没有重新获取时,调用next()方法时:
java.util.ConcurrentModificationException
创建集合
Collection c = new ArrayList();
注意:此时获取的迭代器,指向的是那是集合中没有元素状态下的迭代器。
一定要注意:集合结构只要发生改变,迭代器必须重新获取。
当集合结构发生了改变,迭代器没有重新获取时,调用next()方法时:
java.util.ConcurrentModificationException
Iterator it = c.iterator();
添加元素(在获取了迭代器之后更新的话)
c.add(1); // Integer类型
c.add(2);
c.add(3);
利用迭代器迭代
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
此时就会出现错误!
因为当集合结构发生了改变,迭代器没有重新获取时,调用next()方法时:
java.util.ConcurrentModificationException
迭代器的remove方法
在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素:c.remove(o); 迭代过程中不能这样。
会出现:java.util.ConcurrentModificationException
在迭代元素的过程当中,一定要使用迭代器Iterator的remove方法,删除元素,
不要使用集合自带的remove方法删除元素。
Collection c2 = new ArrayList();
c2.add("abc");
c2.add("def");
c2.add("xyz");
Iterator it2 = c2.iterator();
while(it2.hasNext()){
Object o = it2.next();
删除元素
删除元素之后,集合的结构发生了变化,应该重新去获取迭代器
但是,循环下一次的时候并没有重新获取迭代器
所以会出现异常:java.util.ConcurrentModificationException
出异常根本原因是:集合中元素删除了,但是没有更新迭代器(迭代器不知道集合变化了)
c2.remove(o);
直接通过集合去删除元素,没有通知迭代器。(导致迭代器的快照和原集合状态不同。)
使用迭代器来删除可以吗?
迭代器去删除时,会自动更新迭代器,并且更新集合(删除集合中的元素)。
it2.remove();
删除的一定是迭代器指向的当前元素。
}