集合的概念
概念:对象的容器,定义了对多个对象进行操作的常用方法,可实现数组的功能
和数组的区别:
- 数组的长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型.集合只能存储引用类型
位置:java.util.*;
- 集合只能存放对象,比如存一个int型数据i放入集合中,其实它是自动转换成Integer类后存入的,Java中的每一种基本类型都有对应的引用类型(包装类)
- 集合存放的是多个对象的引用,对象本身还是放在堆内存中
- 集合可以存放不同类型,不限数量的数据类型
- 使用foreach循环遍历
for(数据类型 局部变量:集合名){
//循环内部的局部变量,代表当次循环从集合中取出的对象
}
Collection集合体系
Collection接口
- List接口和Set接口的父接口
- 特点:代表一组任意类型的对象,无序、无下标
- 方法:
//添加一个对象
boolean add(Object obj)
//将一个集合中的所有对象添加到此集合中
boolean addAll(Collection c)
//清空此集合中的所有对象
void clear()
//检查此集合中是否包含o对象
boolean contains(Object o)
//比较此集合是否与指定对象相等
boolean equals(Object o)
//判断此集合是否为空
boolean isEmpty()
//在此集合中移除o对象
boolean remove(Object o)
//删除所有元素
boolean removeAll(Collection c)
//返回此集合中的元素个数
int size()
//将此集合转换成数组
Object[] toArray()
Collection中的高级功能:
- boolean addAll(Collection c):添加一个集合中的所有元素
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> c1 = new ArrayList<String>();
Collection<String> c2 = new ArrayList<String>();
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c2.add("abc4");
c2.add("abc5");
c2.add("abc6");
c1.addAll(c2);
System.out.println(c1);
}
}
- boolean removeAll(Collection c):问题:是删除一个算删除还是删除所有算删除?
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> c1 = new ArrayList<String>();
Collection<String> c2 = new ArrayList<String>();
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc6");
c2.add("abc1");
c2.add("abc2");
c2.add("abc6");
System.out.println("c1c2:"+c1.removeAll(c2));
System.out.println(c1);
}
}
删除所有元素,只要集合中有一个元素被包含,将这个元素从c1删除掉,则返回true
- boolean containsAll(Collection c):问题:包含一个算包含还是包含所有算包含?
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> c1 = new ArrayList<String>();
Collection<String> c2 = new ArrayList<String>();
Collection<String> c3 = new ArrayList<String>();
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc6");
c2.add("abc1");
c2.add("abc2");
c2.add("abc4");
c3.add("abc1");
c3.add("abc2");
c3.add("abc3");
System.out.println("c1c2:"+c1.containsAll(c2));
System.out.println("c1c3:"+c1.containsAll(c3));
}
}
包含所有
- public boolean retainAll(Collection c) 取交集,问题:boolean的真实含义是什么?:
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> c1 = new ArrayList<String>();
Collection<String> c2 = new ArrayList<String>();
Collection<String> c3 = new ArrayList<String>();
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc6");
c2.add("abc1");
c2.add("abc2");
c2.add("abc4");
System.out.println("c1c2:"+c1.retainAll(c2));
System.out.println(c1);
}
}
取c1和c2的交集,并赋给c1,若c1改变则为true,否则为false
迭代器Iterator
-
Iterator iterator():Collection集合的专有遍历方式
-
iterator()的返回值是接口:需要返回的是该接口的子实现类对象!
-
boolean hasNext():判断当前迭代器中是否有下一个可以遍历元素,如果存在,则返回true;
-
Iterator:存在一个方法,Object next():获取下一个元素
-
使用迭代器遍历集合
public class Demo1 {
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
list.add(new Student("奥利给",18));
list.add(new Student("giao",19));
list.add(new Student("画画的贝贝",28));
list.add(new Student("你说嘿我说嘿嘿",21));
Iterator<Student> it = list.iterator();
//判断是否存在下一个元素
while(it.hasNext()) {
//it.next,获取下一个元素
//注意,next方法不能使用多次,使用一次即可,
//能使用for循环,不推荐(因为以后集合中元素可能不知道个数,使用while循环)
System.out.println(it.next());
}
List集合
特点:有序、有下标、元素可以重复
方法
- 除了上面Collection的方法外,还有一些
//在index位置插入对象o
void add(int index,Object o)
//将一个集合中的元素添加到此集合中的index韦志中
boolean addAll(int index,Collection c)
//返回集合中指定位置的元素
Object get(int index)
//返回fromIndex和toIndex之间的集合元素(范围是[fromIndex,toIndex-1)
List subList(int fromIndex,int toIndex)
ListIterator:列表迭代器
- ListIterator listIterator()这个方法底层实现:是通过ArrayList里面的成员内部类
- 正向遍历
boolean hasNext():判断是否有下一个元素
Object next() :获取下一个元素 - 逆向遍历
boolean hasPrevious():判断是否有上一个元素
Object previous():获取前一个元素
//示例
ListIterator<String> lit = list.listIterator() ;
while(lit.hasNext()) {
String s = lit.next() ;
System.out.println(s+"---"+s.length());
}
List集合的遍历方式
- Collection集合的方法 Object[] toArray
- Collection集合的迭代器Iterator iterator()
- size()+Object get(int index):普通for循环
- 列表迭代器:ListIteraotr listiterator()
List接口的三个经典实现
- 1.ArrayList
- 底层数据结构是数组,查询快,增删慢,线程不安全,效率高,JDK1.2版本
- ArrayList里面可以存放null值,元素可以重复(可以有多个null值),可以存储重复元素,存储和取出一致(有序的)!
- ArrayList:单线程程序中考虑执行效率,优先采用!
- 其父类叫做AbstractList
- 应用场景:网络聊天室 查看在线好友列表
List list1 = new ArrayList();
- 2.Vector
- 数组结构实现,查询快,增删慢,运行效率慢,线程安全,JDK1.0版本(这个集合几乎已经淘汰)
- 线程安全的---->同步的---->执行效率低!
- 特有功能:
public void add(int index, E element):插入元素
public Enumeration elements() — 相当于:Iterator iterator()
该接口有两个方法
boolean hasMoreElements():判断是否有下一个元素-----> 相当于:boolean hasNext()
Object nextElement():获取一个元素 -----> 相当于:next()
public Object elementAt(int index):通过角标获取指定的元素---->相当于:Object get(int index)
elementAt()+size() :vector的普通for遍历方式 - 场景:IO流:合并流 SequenceInputStream 可以将多个文件内容读出来复制到指定文件中!
List list2 = new Vector();
- 3.LinkedList
- 链表结构实现,增删快,查询慢,线程不安全,效率高
- 线程不安全的—不同的---->执行效率高!
- 应用场景:网站中 记录用户浏览过商品足迹 (Web技术:Cookie/Session)
- 特有功能
添加
public void addFirst(Object e):将该元素添加到列表的开头!
public void addLast(Object e):将该元素添加到列表的末尾!
删除
public Object removeFirst():删除列表第一个
public Object removeLast():删除列表最后一个
获取
public Object getFirst():获取第一个
public Object getLast() :获取最后一个
List list3 = new LinkedList();
方法
// LinkedList的getFirst()方法是从Deque双向链表中实现的方法
//List对象中并不包含该方法,所以单纯的List对象不能调用getFirst()方法
public E getFirst()
//与此类似的
public E getLast()
//peek()"偷瞄"了一下第一个元素,只是看了一下,不对其进行操作
public E peek()
//pop()"偷瞄"之后还带走了第一个元素
public E pop()
在集合中插入元素
对ArrayList而言(数组结构)
对于LinkedList而言(链表结构)
- 根据上面两图,可以得出,如果数据较多且需要频繁的在集合中间插入元素,优先选择LinkedList
- 如果只是在集合的尾部做元素的追加,优先选择ArrayList
- 必须连续开辟空间,查询快,增删慢
- 无需连续开辟空间,查询慢,增删快
Set集合
特点:无序,无下标,元素不可重复(存储和取出不一致,取决于底层HashMap实例)
方法:全部继承自Collection中的方法
Set的实现类
- 1.HashSet
- 底层hash表结构 来保证元素的唯一性!
- 基于HashCode实现元素不重复
- 存储自定义对象,必须重写hashcode()和equals()
- 当存入元素的哈希码相同时,会调用==或equals进行确认,结果为true,拒绝后者存入
Set set1 = new HashSet();
- 2.LinkedHashSet
- 链表实现的HashSet,按照链表进行存储,即可保留元素的插入顺序
Set set2 = new LinkedHashSet();
- 3.TreeSet
- 本质基于TreeMap的底层实现(红黑树结构---->自平衡"的二叉树结构")
- 基于排序顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
- 有两种排序方式:取决于创建当前Set集合对象的时候的构造方法
public TreeSet():默认的自然顺序排序(无参构造方法:自然排序)
public TreeSet(Comparator<? super E> comparator)TreeSet集合有参构造方法(比较器排序)
Set set3 = new TreeSet();
比较器排序
- 方式1:直接给了创建了接口子实现类MyComparator
TreeSet ts = new TreeSet(new MyComparator()) - 方式2:形参参数如果接口:传入接口的匿名内部类(本质:接口的子实现类)
匿名内部类(推荐的方式)
示例
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//主要条件: 学生年龄的从大到小排序
//s1---->this
//s2---->s
int num = s2.getAge() - s1.getAge() ;
//学生年龄相同,比较姓名是否一样
int num2 = (num==0) ? (s1.getName().compareTo(s2.getName())): num ;
return num2;
}
}) ;
附加题
利用集合List和Set来实现对0-9十个数字的随机排序
public class Random {
public static void main(String[] args) {
//创建list集合
List<Integer> list = new ArrayList<Integer>();
//创建set集合
Set<Integer> set = new HashSet<Integer>();
//当set集合中的元素个数小于10的时候,执行此循环
while(set.size()<10) {
//使用Math的random方法创建随机数
//随机数的范围为0-9
int num = (int)(Math.random()*10);
//如果set集合追加成功(追加的元素不重复)
if(set.add(num)) {
//把该元素追加给list集合
list.add(num);
}
}
//打印list集合,这样就实现了随机排序
System.out.println(list);
}
}