Java中的集合体系之Collection接口(上)

Java中的集合体系之Collection接口(上)

一、引入
1.集合,数组都是对多个数据进行存储操作的结构,简称为JAVA容器。此时说的存储,主要指的是内存层面上,不涉及到持久化的存储。
2.1数组存储数据的特点:
1.数组一旦初始化之后,长度就确定了
2.数组一旦定义好之后,它的元素类型也就确定了,我们也就只能操作指定类型的数据了,例如:String[] arr1; int[] arr2; Object[] arr3;
2.2数组存储数据的缺点:
1.一旦初始化之后,其长度不可修改。
2.数组中提供的方法非常有限,对于增删改查等操作,非常不方便,同时效率也不高。
3.获取数组中实际元素的个数的需求,数组没有现成的属性或者方法可用
4.数组存储数据的特点:是有序,可重复的;所以对于无序不可重复的需求不能
满足。
二、java中的集合体系
1.Collection接口
位于java.util包下的Collection接口。单列集合,存储单列数据,用来存储一个一个的对象。
1)List子接口:存储有序的,可重复的数据(也称之为:动态数组)
①ArrayList:是List接口的实现类,底层存储是数组,线程不安全,效率高
②LinkedList:是List接口的实现类,底层存储是双向链表,线程不安全,效率高
③Vector:是List接口的实现类,底层存储是数组,线程安全,效率低
2)Set子接口:存储的是无序的,不可重复的数据(符合高中的集合)
①HashSet:是Set接口的实现类,使用hash表(数组)存储元素
②LinkedHashSet:是Set接口的实现类,链表维护元素的插入次序
③TreeSet:是Set接口的实现类,用来排序

package com.zretc.java;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.junit.Test;
public class CollectionTest {

 @Test
 public void methodTest1() {
System.out.println("methodTest1:");
 //首先:通过多态的方式创建Collection引用的集合
 Collection col1 = new ArrayList();
 
 //1.int size();返回集合中的个数
 System.out.println(col1.size() + "个元素");//0个元素
 
 //2.boolean add(Object obj);向集合中添加一个元素,存储的是Object
//类型(在没有添加泛型的时候)
 //注意:当确认集合泛型的时候,存储的是确认后的泛型类型
 col1.add("张三");
 col1.add(12);
 col1.add(new Person("Amy",11));
 
 //测试:此时集合内的元素个数。
 System.out.println(col1.size() + "个元素");//3个元素
 System.out.println(col1.toString());//集合中重写了toString方法,输出[张三, 12, Person [name=Amy, age=11]]
 
 //3.boolean addAll(Collection col):将形参中的集合中的所有元素添加
//到当前集合中
 Collection col2 = new ArrayList();
 col2.addAll(col1);
 col2.add("第二个集合");
 System.out.println(col2);//[张三, 12, Person [name=Amy, age=11], 第二个集合]
 System.out.println(col2.size() + "个元素");//4个元素
 
 //4.boolean isEmpty():判断当前集合是否为空
 System.out.println(col1.isEmpty());//false 不为空
 
 //5.void clear();清空当前集合
 col1.clear();
 System.out.println(col1.isEmpty());//当前集合为空,返回true
 System.out.println();
 }
 
 @Test
 public void methodTest2() {
System.out.println("methodTest2:");
 Collection col1 = new ArrayList();
 Date date = new Date();
 col1.add(123);
 col1.add("aa");
 col1.add(new String("bb"));
 col1.add(date);
 col1.add(new Person("tony",2));
 
 //6.boolean contains(Object obj);判断集合中是否包含某元素,若包含
//返回true,否则返回false
 //注意1:该方法的判断依据是所在类的equals方法
 //注意2:如果集合中存入的元素是自定义类,要求自定义类的equals方法必
//须重写,
 //否则会按照Object类中的equals方法执行。
 boolean b = col1.contains(123);//true
 b = col1.contains("aa");//true
 b = col1.contains(new String("bb"));//ture
 b = col1.contains(new Person("tony",2));//false
 System.out.println(b);
 
 //7.boolean containsAll(Collection col):判断是否包含col集合
 Collection col2 = new ArrayList();
 col2.add(123);
 col2.add("aa");
 col2.add(456);
 //col1集合中是否包含col2集合中的全部元素
 System.out.println(col1.containsAll(col2));//false
 
 //8.boolean retainAll(Collection col):
 //返回当前集合和col集合的公共部分的元素,返回给当前集合
 System.out.println(col1);//[123, aa, bb, Wed Jan 26 14:52:43 CST 2022, Person [name=tony, age=2]]
 System.out.println(col2);//[123, aa, 456]
 col1.retainAll(col2);
 System.out.println(col1);//[123, aa]
 
 //9.boolean remove(Object o):删除集合中的某个元素,根据equals删
 boolean b1 = col1.remove(new Person("tony",2));
 System.out.println(b1);//false
 System.out.println(col1);//[123, aa]
 
 //10.boolean removeAll(Collection col);从当前集合中删除包含在col
//中的元素
 System.out.println(col2);//[123, aa, 456]
 col1.removeAll(col2);
 System.out.println(col1);//[]
 System.out.println();
 }
 
 @SuppressWarnings({ "rawtypes", "unchecked" })
 @Test
 public void methodTest3() {
System.out.println("methodTest3:");
 Collection col1 = new ArrayList();
 Date date = new Date();
 col1.add(123);
 col1.add("aa");
 col1.add(new String("bb"));
 col1.add(date);
 col1.add(new Person("tony",2));
 
 //11.boolean equals(Object obj):判断两个集合中的元素是否相同
 Collection col2 = new ArrayList();
 col2.add(123);
 col2.add("aa");
 col2.add(new String("bb"));
 col2.add(date);
 col2.add(new Person("tony",2));
 
 System.out.println(col1.equals(col2));//false
 
 //12.hashCode():返回当前对象的哈希值,一串地址。
 System.out.println(col1.hashCode());//941605507
 
 //小扩展:将一个数字转换为一个十六进制的字符串
 
System.out.println(Integer.toHexString(col1.hashCode()));//381fc283
 
 //13.集合--->数组 object[] toArray();
 Object[] objs = col1.toArray();
 for(int i = 0; i< objs.length;i++) {
 System.out.println(objs[i]);
 }
// 123
// aa
// bb
// Wed Jan 26 15:07:05 CST 2022
// Person [name=tony, age=2]
 
 //小扩展:数组--->集合 Arrays.asList()
 String[] strs = {"AA","BB","CC","DD"};
 List<String> list = Arrays.asList(strs);
 System.out.println(list);//[AA, BB, CC, DD]
 
 List list2 = Arrays.asList(new int[] {1,2,3});
 System.out.println(list2);//结果是一个地址值 [[I@46ee7fe8]
 
 List list3 = Arrays.asList(new Integer[] {1,2,3});
 System.out.println(list3);//[1,2,3]
}

}
class Person {
 private String name;
 private Integer age;
 
 
 public Person() {
 super();
 }
 public Person(String name, Integer age) {
 super();
 this.name = name;
 this.age = age;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public Integer getAge() {
 return age;
 }
 public void setAge(Integer age) {
 this.age = age;
 }
 @Override
 public String toString() {
 return "Person [name=" + name + ", age=" + age + "]";
 }
}

2.Collection集合遍历操作
1)Iterator接口
①Iterator接口概述 :Iterator对象称为迭代器,主要用来遍历Collection集合中的元素,Map接口不适用;
②Collection接口继承了java.lang.Iterable接口,该接口有一个iterator(),该方法返回一个迭代器的对象,那么就是证明所有Collection接口的实现类都拥有这个iterator()。

package com.zretc.java;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.junit.Test;
public class IteratorTest {
 @SuppressWarnings({ "rawtypes", "unchecked" })
 @Test
 public void test1() {
 Collection col1 = new ArrayList();
 col1.add(123);
 col1.add("aa");
 col1.add(new String("bb"));
 col1.add(new Person("tony", 2));
 
 //1.创建迭代器对象。
 Iterator iterator = col1.iterator();
// System.out.println(iterator.next());123
// System.out.println(iterator.next());aa
// System.out.println(iterator.next());bb
// System.out.println(iterator.next());Person [name=tony, age=2]
 
 //方式1:不推荐
 for (int i = 0; i < col1.size(); i++) {
 System.out.println(iterator.next());
 }
 
 //方式2:推荐使用方式
 //①hasNext():判断是否有下一个元素
 while (iterator.hasNext()) {
 //②next():指针下移;将下移后的集合位置上的元素返回
 System.out.println(iterator.next());
// 123
// aa
// bb
// Person [name=tony, age=2]
 }
 }
}

2)Iterator的执行原理
第一步:使用iterator.hasNext()来确认是否有下一个元素
第二步:确认有元素之后,通过iterator.next()干两件事
①指针下移
②将指针指向的位置的元素进行返回

3)Iterator常见错误写法

 @SuppressWarnings({ "rawtypes", "unchecked" })
 @Test
 public void teat2() {
 Collection col1 = new ArrayList();
 col1.add(123);
 col1.add("aa");
 col1.add(new String("bb"));
 col1.add(new Person("tony", 2));
 
 //第一种错误写法:结果跳着显示,因为该while代码块调用两次iterator.next()
// aa
// Person [name=tony, age=2]
// Iterator iterator = col1.iterator();
// while(iterator.next() != null) {
// System.out.println(iterator.next());
// }
 
 //第二种错误写法:
 //集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认的指针都在集合的第一个元素之前。
 while (col1.iterator().hasNext()) {//死循环
 System.out.println(col1.iterator().next());// 每次都输出第一个元素
 
 }
}

4)remove()方法
Iterator内部定义了remove()方法,可以在遍历的时候,删除集合中的元素。此方法不同于集合直接调用remove(),
在没有调用next()之前,就先remove,报异常IllegalStateException。已经调用完一次remove方法之后,再调用就会报错

 @SuppressWarnings({ "rawtypes", "unchecked" })
 @Test
 public void test3() {
 Collection col1 = new ArrayList();
 col1.add(123);
 col1.add("aa");
 col1.add(new String("bb"));
 col1.add(new Person("tony", 2));
 
 Iterator iterator = col1.iterator();
 while (iterator.hasNext()) {
 //在没有调用next()之前,就先remove,报异常IllegalStateException。
// iterator.remove();
 Object obj = iterator.next();

 if("aa".equals(obj)) {
 iterator.remove();
 //已经调用完一次remove方法之后,再调用就会报错
 iterator.remove();//报错
 }
 }
 //遍历集合
 iterator = col1.iterator();
 while(iterator.hasNext()) {
 System.out.println(iterator.next());
 }
 }

5)foreach增强for循环
JDK5.0新增foreach循环,用于遍历数组和集合
语法:
在这里插入图片描述
执行流程:
自动去取集合对象的元素,先取第一个值,赋值给局部变量,然后输出局部变量,然后再取第二个值,再赋值给局部变量,然后输出局部变量……
注意:
当我们debug的时候,进去到foreach循环中,发现其实调用的还是迭代器。

 @SuppressWarnings({ "rawtypes", "unchecked" })
 @Test
 public void test1() {
 Collection<Integer> col1 = new ArrayList<Integer>();
 col1.add(123);
 col1.add(456);
 col1.add(789);
 col1.add(333);
 col1.add(444); 
//使用增强for循环
//形式上虽然是增强for循环,但是内部仍然调用了迭代器
 for(Integer i : col1) {
 System.out.println(i);
 }
// 123
// 456
// 789
// 333
// 444
 //当一个集合元素没有泛型规定时,传入的集合数据类型是Object
 //for(Object obj : col1) {
 // System.out.println(obj);
 //}
 
 }

6)list接口的特点
(1)是Collection子接口之一,是JDK1.2的时候出现的;
(2)鉴于java中数组存储数据的局限性,我们通常使用List来代替数组,我们称之为动态数组。‘
(3)List集合中的元素都是有序,且可重复的,集合中的每个元素都有其对应的顺序索引。
(4)JDK API中List接口的实现类常用的有:ArrayList、LinkedList和Vector
三个实现类的区别:
①相同点:三个类都是实现了List接口,存储数据的特点相同:存储有序的,可重复的数据
②不同点:
ArrayList:在JDK1.2的时候出现,作为List接口的主要实现类,线程不安全,效率高,底层使用Object[] elementData进行存储。
LinkedList:在JDK1.2的时候出现,对于频繁的插入,删除的操作,效率会高
于ArrayList;底层是使用双向链表进行存储。
Vector:在JDK1.0的时候出现,作为List接口的古老实现类,线程安全的,但是效率低,底层使用Object[] elementData存储数据。

7)双向链表底层是如何存储的?
(1)使用双向链表存储—插入操作
在这里插入图片描述
(2)使用双向链表存储—删除操作
在这里插入图片描述
8)底层区别
(1)ArrayList,查找,加入,遍历更适合ArrayList。
底层原理:JDK1.8当创建对象的时候,底层Object[] elementData初始化为{},并没有像JDK1.7的时候创建长度为10的数组,而是在.add添加元素的时候,底层创建了一个长度为10的数组,并且将值添加到elementData[0]。当继续添加元素,使得原本的数组容量不够的时候,就扩容;默认情况是:扩容为原来的1.5倍,同时需要将原有数组复制到新的数组中。之
前的数组就会被废弃。
注意:使用无参构造不断扩容会导致程序效率低,如果知道要存储到集合的数据大致
的数量,可以直接使用单参构造;当创建对象的时候,直接给你对应的数据空间,效
率会高一点。

public ArrayList(int initialCapacity) {
 if (initialCapacity > 0) {
 this.elementData = new Object[initialCapacity];
 } else if (initialCapacity == 0) {
 this.elementData = EMPTY_ELEMENTDATA;
 } else {
 throw new IllegalArgumentException("Illegal Capacity:
"+
 initialCapacity);
 }
 }

(2)LinkedList,插入,删除操作更适合LinkedList
底层原理:内部声明了Node类型的first和last属性,默认值是null;当集合对象.add(123),会将123封装到Node中,创建Node对象;其中Node定义体现了LinkedList双向链表的说法。

private static class Node<E> {
 E item;
 Node<E> next;
 Node<E> prev;
 Node(Node<E> prev, E element, Node<E> next) {
 this.item = element;
 this.next = next;
 this.prev = prev;
 }
 }

(3)Vector,JDK1.7&JDK1.8通过Vector()构造器创建对象的时候,底层都会创建长度为10的数组在扩容方面,默认扩容为原来数组长度的2倍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想学摄影的IT男

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值