之前介绍的数组可以用来存储类型相同的确定数量的一组数据,如果并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象又该怎么办呢?这时候就可以使用Java集合框架了
Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于 java.util 包中
一、集合相关接口简介- Collection 接口存储一组不唯一,无序的对象
- List 接口继承了 Collection 接口,存储一组不唯一,有序(插入顺序)的对象
- Set 接口继承了 Collection 接口,存储一组唯一,无序的对象,可以用于集合去重
- Iterator 接口,迭代器,Collection 接口的 iterator() 方法可以获取 Iterator
常用方法1)boolean hasNext():判断是否存在另一个可访问的元素
常用方法2)Object next():返回要访问的下一个元素 - Map 接口存储一组键值对象,无序,提供 key 到 value 的映射,key 值唯一
ArrayList 类和 LinkedList 类都实现了 List 接口,可以存储不唯一、有序的对象
1. ArrayList 类
ArrayList 实现了长度可变的数组,数据存放的先后顺序-1就是下标(删除元素后自动补位),在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高
ArrayList 的增删改查:
public class TestArrayList {
public static void main(String[] args) {
//1.创建集合对象
ArrayList newsList = new ArrayList();
//2.创建新闻对象(News类很简单,代码就不放出来了,就两个属性:title,date)
News n1 = new News("南京新闻", "2021-11-16");
News n2 = new News("北京新闻", "2021-11-16");
News n3 = new News("上海新闻", "2021-11-16");
//3.将对象添加到集合
newsList.add(n1);
newsList.add(n2);
newsList.add(n3);
//4.增强for循环遍历
for (Object object : newsList) {
//打印新闻标题
News n = (News) object;
System.out.println(n.getTitle());
}
//api方法
//打印集合内元素个数
System.out.println(newsList.size());
//是否包含n1
System.out.println(newsList.contains(n1));
//获取索引为1的元素并打印其标题
System.out.println(((News)newsList.get(1)).getTitle());
//修改集合元素
News n4 = new News("天津新闻", "2021-11-16");
newsList.set(1, n4);
//删除集合元素
newsList.remove(1);
newsList.remove(n4);
//判断集合是否为空
System.out.println(newsList.isEmpty());
//清空集合并再次判断是否为空
newsList.clear();
System.out.println(newsList.isEmpty());
//集合转数组
Object[] objects = newsList.toArray();
for (Object object : objects) {
News n = (News) object;
System.out.println(n.getTitle()+""+n.getDate());
}
//迭代器遍历
//1.将集合转换成迭代器对象,对象里面存储了集合的数据
Iterator it = newsList.iterator();
//2.通过迭代器对象的方法进行遍历
while(it.hasNext()) {
//3.获取迭代器中的元素
News n = (News) it.next();
//4.打印标题
System.out.println(n.getTitle());
}
}
}
ArrayList 常用方法:
2. LinkedList 类
LinkedList 采用链表存储方式,大容量数据处理时,插入、删除元素时效率比较高
LinkedList 常用方法:
小结:
List 集合存储一组有可能重复的有序的数据,其中数据查询操作较多的优先选择 ArrayList 集合,数据容量大且增删操作较多的优先选择 LinkedList 集合
三、Set 接口的常用实现类HashSet 类和 TreeSet 类都实现了 Set 接口,可以存储一组唯一,无序的对象
其实,TreeSet 并不是 Set 接口的实现类,它是通过继承 AbstractSet 类来实现 Set 接口的。另外由于 TreeSet 我不怎么用,就不多介绍了,这里就简单介绍一下 HashSet 类吧
因为 HashSet 存放的数据无序,所以他不存在下标,不能查询指定元素,只能遍历;该类也没有提供修改元素的方法(个人认为,反正无序,要是真想修改,直接删除原有元素再新增即可)
HashSet 的增、删、遍历:
public class TestSet {
public static void main(String[] args) {
//1.创建集合对象
Set mySet = new HashSet();
//2.存储数据
mySet.add(1);
mySet.add(2);
mySet.add(3);
mySet.add(4);
mySet.add(5);
//3.打印长度
System.out.println(mySet.size());
mySet.add(6);
mySet.add(1);
System.out.println(mySet.size());
//4.删除元素
mySet.remove(4);
//5.遍历
for (Object object : mySet) {
System.out.println(object);
}
//6.使用迭代器遍历
//1)转换成迭代器对象
Iterator it = mySet.iterator();
//2)通过迭代器对象的方法进行遍历
while(it.hasNext()) {
//3)获取迭代器中的元素并打印
System.out.println(it.next());
}
}
}
从 HashSet 源码可知,其底层原理利用的是 HashMap,HashMap 存储的是无序且 key 值唯一的键值对,HashSet 取的就是 HashMap 的 key,所以 HashSet 自带去重效果。
public class No_repeat {
public static void main(String[] args) {
//利用set去重复,把不重复的元素放入list集合中
List oldList = new ArrayList();
oldList.add(1);
oldList.add(1);
oldList.add(2);
oldList.add(2);
oldList.add(3);
oldList.add(7);
for (Object object : oldList) {
System.out.println(object);
}
System.out.println("======去重后======");
//通过set巧妙的去重
Set mySet = new HashSet();
//1.把list数据装入set,再装入的过程中,set自动去重
mySet.addAll(oldList);
//2.把oldlist清空,重新装入set里面的内容
oldList.clear();
oldList.addAll(mySet);
for (Object object : oldList) {
System.out.println(object);
}
System.out.println(oldList);
System.out.println(mySet);
}
}
四、Map 接口的常用实现类
HashMap 类和 TreeMap 类都实现了 Map 接口,可以存储一组无序且 key 值唯一的键值对
其实,TreeMap 并不是 Map 接口的实现类,它是通过继承 AbstractMap 类来实现 Map 接口的。另外由于 TreeMap 我不怎么用,就不多介绍了,这里就简单介绍一下 HashMap 类吧
HashMap 是通过数组+链表的结构实现的,结合了数组和链表的优点。当链表长度超过其阈值时,链表转换为红黑树
HashMap 的初始容量是默认 16,可以自定义,最大值为 1<<30,扩容的负载因子为 0.75,链表长度的阈值为 8,源码如下:
HashMap 的增删改查:
public class TestMap {
public static void main(String[] args) {
//1.创建集合对象
HashMap newsMap = new HashMap<>();
//2.创建新闻对象
News n1 = new News("南京新闻", "2021-11-16");
News n2 = new News("北京新闻", "2021-11-16");
News n3 = new News("上海新闻", "2021-11-16");
//3.将对象添加到集合(增改)
newsMap.put(1, n1);
newsMap.put(2, n2);
newsMap.put(3, n3);
//4.删查
//查询--查询1键对应的新闻并打印新闻标题
System.out.println(newsMap.get(1).getTitle());
//删除--删除键为2的数据
newsMap.remove(2);
//遍历
//hashmap可以获取键集,值集
System.out.println(newsMap.keySet());
System.out.println(newsMap.values());
System.out.println(newsMap);
System.out.println(newsMap.entrySet());
//遍历1.使用entrySet增强for循环遍历
System.out.println("遍历一============");
Set> newsSet = newsMap.entrySet();
for (Entry entry : newsSet) {
System.out.println(entry.getKey() + "--" + entry.getValue().getTitle());
}
//遍历2.使用key增强for循环遍历
System.out.println("遍历二============");
Set keys = newsMap.keySet();
for (Integer key : keys) {
System.out.println(newsMap.get(key).getTitle());
}
//遍历3.使用key迭代器循环遍历
System.out.println("遍历三============");
Iterator it = newsMap.keySet().iterator();
while(it.hasNext()) {
//it.next()只能出现1次,否则会往后递推,导致NoSuchElementException异常
System.out.println(newsMap.get(it.next()).getTitle());
}
//遍历4.使用values迭代器循环遍历
System.out.println("遍历四============");
Iterator it2 = newsMap.values().iterator();
while(it2.hasNext()) {
System.out.println(it2.next().getTitle());
}
//遍历5.使用values增强for遍历
System.out.println("遍历五============");
Collection values = newsMap.values();
for (News news : values) {
System.out.println(news.getTitle());
}
//遍历6.使用entrySet迭代器循环遍历
System.out.println("遍历六============");
Iterator> it3 = newsMap.entrySet().iterator();
while(it3.hasNext()) {
System.out.println(it3.next().getKey()+"--"+it3.next().getValue());
}
}
}
HashMap 常用方法:
为了避免强制类型转换时一些易出现的异常,JDK5.0 使用泛型改写了集合框架中的所有接口和类
泛型集合可以约束集合内的元素类型,泛型集合中的数据不再自动转换为Object
//下例中的 students 已经限定了是 Student 类型的集合,添加非 Student 类对象则会报错 ArrayListstudents = new ArrayList ();
注:添加泛型只对元素类型做了约束,其他并无影响
六、Collection 接口和 Collections 类Collection 接口是集合类的接口,是 List 接口和 Set 接口的父接口,其他常用的通用方法:clear()、isEmpty()、iterator()、toArray()、addAll(Collection c)……
Collections 类是集合的操作类,是一个工具类,Java集合框架将针对不同数据结构算法的实现都保存在工具类中,Collections 类定义了一系列用于操作集合的静态方法,如 sort():排序;binarySearch():查找;max()/min():查找最大/最小值……可以对集合进行排序、查找和替换操作
Collections 排序示例:
public class TestCollections {
public static void main(String[] args) {
//基本数据类型排序
List numslist = new ArrayList<>();
numslist.add(22);
numslist.add(8);
numslist.add(17);
numslist.add(23);
numslist.add(18);
numslist.add(9);
numslist.add(12);
System.out.println("排序前=======");
for (Object object : numslist) {
System.out.print(object + " ");
}
//排序
Collections.sort(numslist);
System.out.println();
System.out.println("排序后=======");
for (Object object : numslist) {
System.out.print(object + " ");
}
//对象排序:需要重写 toString() 方法和 compareTo() 方法
List newslist = new ArrayList<>();
News2 n1 = new News2("1001","南京新闻", "2021-11-16");
News2 n2 = new News2("1002","北京新闻", "2021-11-16");
News2 n3 = new News2("1003","上海新闻", "2021-11-16");
newslist.add(n3);
newslist.add(n1);
newslist.add(n2);
System.out.println("排序前======");
for (News2 news2 : newslist) {
System.out.println(news2.toString());
}
//排序
Collections.sort(newslist);
System.out.println("排序后======");
for (News2 news2 : newslist) {
System.out.println(news2.toString());
}
}
}
实现一个类的对象之间比较大小,该类要实现 Comparable 接口并重写 compareTo() 方法
// News2 类 public class News2 implements Comparable{ private String ID; private String title; private String date; public News2(String ID,String title, String date) { super(); this.ID = ID; this.title = title; this.date = date; } public News2(){} public String getID() {return ID;} public void setID(String iD) {ID = iD;} public String getTitle() {return title;} public void setTitle(String title) {this.title = title;} public String getDate() {return date;} public void setDate(String date) {this.date = date;} @Override public String toString() { return "News2 [ID=" + ID + ", title=" + title + ", date=" + date + "]"; } @Override public int compareTo(News2 o) { //同一个对象 相等 if(this == o) { return 0; //不是同一个对象 比较新闻id大小 }else if(Integer.parseInt(this.ID) > Integer.parseInt(o.ID)) { return 1; }else if(Integer.parseInt(this.ID) == Integer.parseInt(o.ID)) { return 0; }else { return -1; } } }



