场景
当数据多了要进行存储时,需要一个容器,存储固定长度的数据可以使用数组。但是如果数据的个数不确定,再使用数组就较为繁杂。Java就引入了另外一个可变的容器 ---- 集合
在1.2版本之后,随着功能和需求的增多,将其不同种类的共性向上抽取,形成了体系,就出现了集合框架,有了更多种类的集合容器,用来完成不同的需求。这些集合容器是通过数据结构(存储数据的一种方式)来进行区分。集合框架的最顶层是一个接口collection(最基本的共性)。
1 数组和集合的区别
(1)数组的长度是固定的,集合的长度是可变的
(2)数组中存储的是同一类型数据,集合存储的都是对象
2 接口(collection)
Collection 层次结构 中的根接口。集合是将多个元素组成一组对象,这些对象也称为 collection 的元素。
特点:
集合的长度没有限制,可以存放任意多的元素,而且元素的数据类型也可以不同。
2.1 调用Collection不带All的方法
// Collection是一个接口类型的容器,不可创建对象。只能通过多态创建对象
Collection coll = new ArrayList();
// 添加对象
coll.add("coco");
coll.add("xiaoran");
coll.add("nana");
// 移除对象
coll.remove("nana");
// 接口重写toString方法,输出集合内容(toString可省略)
System.out.println(coll.toString());
// 结果:[coco, xiaoran]
// isEmpty();判断集合是否为空。空---true,不为空---false
System.out.println(coll.isEmpty());
// 结果:false
// contains(object o);判断集合是否包含指定的元素
System.out.println(coll.contains("coco"));
// 结果:false
// size();返回此 collection 中的元素个数
System.out.println(coll.size());
// 结果:2
// clear();格式化,移除此 collection 中的所有元素(可选操作)
coll.clear();
System.out.println(coll.toString());
// 结果:[]
2.2 调用Collection集合带All的方法
public static void main(String[] args) {
// 创建两个集合容器
Collection coll1 = new ArrayList();
Collection coll2 = new ArrayList();
// 向两个容器添加元素
coll1.add("abc1");
coll1.add("abc2");
coll1.add("abc3");
coll2.add("abc3");
coll2.add("abc4");
coll2.add("abc5");
//(1)addAll(Collection c);将集合2所有元素添加到集合1中
coll1.addAll(coll2);
// 输出集合结果:[abc1, abc2, abc3, abc3, abc4, abc5]
//(2)containsAll(Collection c);如果集合1包含集合2所有元素,则返回 true。
boolean b = coll1.containsAll(coll2);
System.out.println(b);
// 结果:true
//(3)removeAll(Collection c);移除集合1中和集合2的相同元素
boolean c = coll1.removeAll(coll2);
System.out.println(c);
// 结果:true 输出集合结果:[abc1, abc2]
//(4)retainAll(Collection c);保留集合1中和集合2的相同元素
boolean d = coll1.retainAll(coll2);
System.out.println(d);
// 结果:true 输出集合结果:[]
// 输出集合容器
System.out.println(coll1);
// 结果:[]
System.out.println(coll2);
// 结果:[abc3, abc4, abc5]
}
3 集合的取出方式(接口Iterator)
由于集合框架中每个集合容器存储方式不同,就需要建立不同的遍历方法。但是我们的目的是一个一个的取出元素,java引入了迭代器机制,来对不同集合元素的进行遍历。
迭代:无论是什么数据结构,最终的取出方式就是一个个的取,取之前先判断,有就取一个,没有就结束了
(1)hasNext()方法,如果迭代器对象中有元素,则返回true ,反之false
(2)next()方法,返回迭代的下一个元素
public static void main(String[] args) {
// 1.创建集合对象
Collection c = new ArrayList();
c.add("abc1");
c.add("abc2");
// 2.取出集合中的元素,
// 集合中有iterator方法通过集合获取迭代器对象
Iterator it = c.iterator();
// 3.使用迭代器对象的方法来获取集合中的元素
// System.out.println(it.next());
// System.out.println(it.next());
// 3.1改进方法(1)while循环(2)for循环。后者更加节省空间
// 方法一:while循环
while(it.hasNext()){
System.out.println(it.next());
}
System.out.println("===============");
// 方法二:for循环
for (Iterator it1 = c.iterator(); it1.hasNext();) {
System.out.println(it1.next());
}
}
4 集合的细节问题
(1)集合存储的是什么
(2)集合可以存储基本数值吗?
(3)怎么调用某个具体对象的特有方法?
public static void main(String[] args) {
Collection c = new ArrayList();
/*
* c.add("abc1");
* 1 集合中存储的是什么?其实存储的都是对象的地址
*/
/* c.add(1);
* 2 集合中可以存储基本数值吗?不可以,只能是对象。
* 但是jdk1.5引入自动装箱之后可以直接写,
* 但其底层存储还是对象(基本数据类型包装类对象)
* 等价于c.add(Integer.valueOdd(1));
*/
/*
* 3 往集合中存元素,迭代到的元素都是Object对象。
* 需要使用到集合中某个具体对象的本身方法时,就需要Object对象向下转型
*/
c.add("tan1");
c.add("zhou2");
for (Iterator it = c.iterator(); it.hasNext();) {
// 想打印集合中字符串的长度length();
Object obj = it.next();
// 想要使用字符串的方法 ,需要向下转型成String对象
String str = (String)obj;
System.out.println(str.length());//结果:4 5
}
5 重写equals()方法
(1)源码
(2)测试类
为什么要重写equals()方法?
从集合的定义可知,集合中存储的是对象。一些collection允许有重复的元素,而另一些则不允许。
但是无论学生的名字和年龄是否相同,每次创建对象后的地址都是不相同的。
我们想要的是只要同姓名,同年龄一样,这两个对象就是相等的。
判断两个对象是需要通过equals()方法进行比较,因此我们可以自定义比较方法方法。重写equals()方法,建立自己比较的依据。类似于String对象的equals(),只要内容相同即可。
注意:List允许有重复的元素,重复指的是两个对象相等。coll.add()里面传入同一个引用变量叫重复。如果是创建两个对象,对象的名字和年龄相同不叫重复。因此此处要重写equals()方法,使其符合逻辑。即当姓名和年龄相同的对象才叫重复。