20、JAVA进阶——集合(1)

简介: 20、JAVA进阶——集合(1)

一、认识集合


       (1)开发应用程序时,如果想存储多个同类型的数据,可以使用数组来实现;但是使用数组存在如下一些明显缺陷:


               -->数组长度固定,不能很好地适应元素数量动态变化的情况。


               -->可通过数组名.length获取数组的长度,却无法直接获取数组中实际存储的元素个数。


               -->数组采用在内存中分配连续空间的存储方式存储,根据元素信息查找时效率比较低,需要多次比较。


       (2)从以上分析可以看出数组在处理一些问题时存在明显的缺陷,针对数组的缺陷,Java提供了比数组更灵活、更实用的集合框架,可大大提高软件的开发效率,并且不同的集合可适用于不同应用场合。


       (3)Java集合框架提供了一套性能优良、使用方便的接口和类,它们都位于java.util包中,其主要内容及彼此之间的关系如下图所示。


1.gif

1.gif



       (4)从上图可以看出,Java的集合类主要由Map接口和Collection接口派生而来,其中Collection接口有两个常用的子接口,即List接口和Set接口,所以通常说Java集合框架由3大类接口组成(Map接口、List接口和Set接口)。


二、List接口


       ~  Collection接口是最基本的集合接口,可以存储一组不唯一、无序的对象。


       ~  List接口继承自Collection接口,是有序集合。用户可以使用索引(下标)访问List接口中的元素,类似于数组。


       ~  List接口中允许存放重复元素,也就是说List可以存放一组不唯一、有序的对象。


       ~  List接口常用的实现类有ArrayList和LinkedList。


1、 使用ArrayList类动态存储数据

       (1)针对数组的一些缺陷,Java集合框架提供了ArrayList集合类,对数组进行了封装,实现了长度可变的数组,而且和数组采用相同的存储方式,在内存中分配连续的空间,如下图所示,所以,经常说ArrayList为动态数组。


       但是它不等同于数组,ArrayList集合中可以添加任何类型的数据,并且添加的数据都将转换成Object类型,而在数组中只能添加同一类型的数据。


//创建3个NewsTitle类对象
  NewsTitle nt1 = new NewsTitle(1001, "新闻一", "作者1");
  NewsTitle nt2 = new NewsTitle(1002, "新闻二", "作者2");
  NewsTitle nt3 = new NewsTitle(1003, "新闻三", "作者3");
  //数据准备好了,接下来要准备一个集合容器,使用ArrayList
  ArrayList al = new ArrayList();


 (2)ArrayList类提供了很多方法用于操作数据,下表列出的是ArrayList类的常用方法。

1.gif

各方法具体用法代码展示:

//将数据存储到集合中,使用ArrayList类中的add()方法将数据存储到集合中
  al.add(nt1);
  al.add(nt2);
  al.add(nt3);
  al.add(nt2);
  //讲数据存储到集合中的指定位置:add(int index,Object obj)
  al.add(2, nt1);
  //接下来对集合中元素的操作,都是通过集合对象名al调用方法来实现
  //1)获取集合中的元素个数:size()
  int size =al.size();
  System.out.println("al集合中元素个数:"+size);
  //2)获取集合中某个指定下标的元素:get(int index)
  //获取集合中的第一个元素
  /*
   * 在NewsTitle类没有重写toString()方法的时候,通过al.get()方法获取集合中元素,直接输出这个元素,得到的是一个地址值
   * 因为直接输出对象和通过对象调用toString(),这个toString()是Object类中的toString()方法,输出的都是地址值
   * 输出地址没有任何意义,所以会在NewsTitle类中重写toString()方法
   * 
   * 因为在NewsTitle类中重写了toString()方法,通过al.get()方法获取集合中的元素,虽然得到的类型是Object类型
   * 但是在输出对象的时候,调用的是NewsTitle类重写后的toString();
   */
  Object obj1 =al.get(0);
  //System.out.println(obj1);
  NewsTitle nt = (NewsTitle)obj1;
  System.out.println(nt);
  System.out.println("---------------------------");
  //3)遍历集合中的元素
  for(int i =0;i
    Object object=al.get(i);
    NewsTitle newsTitle = (NewsTitle)object;
    System.out.println(newsTitle);
  }
  //4)判断集合中是否包含某一个元素:contains()
  boolean result1 = al.contains(nt3);
  System.out.println("集合中包含nt3这个元素:"+result1);
  //5)删除集合中的元素:remove(元素名)/remove(元素下标)
  boolean result2 =al.remove(nt3);
  System.out.println("元素删除成功:"+result2);
  System.out.println("****************************************");
  //删除后使用增强for循环遍历集合
  for(Object object:al){
    NewsTitle newsTitle = (NewsTitle)object;
    System.out.println(newsTitle);
  }
  System.out.println("****************************************");
  Object obj=al.remove(1);
  System.out.println(obj);
  System.out.println("****************************************");
  //删除元素后使用迭代器遍历集合:iterator()
  /*
   * Iterator:迭代器,可以将它看成是集合容器
   * 将集合al中得元素转移到了Iterator中
   * 接下来使用hasNext()方法判断Iterator容器中是否有元素,如果有返回true,那么就调用next()方法取出集合中的元素
   * 如果hasNext()方法返回false,说明Iterator容器中没哟元素
   * 
   * 
   */
  Iterator it =al.iterator();
  //从it容器中取出元素
  while(it.hasNext()){
    Object object =it.next();
    NewsTitle ntt = (NewsTitle)object;
    System.out.println(ntt);
  }
  //判断集合是否为空:isEmpty()
  boolean result3 =al.isEmpty();
  System.out.println("集合为空:"+result3);
  System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
  //将集合中的元素转换为数组:toArray()
  Object[] objs=al.toArray();
  for (int i = 0; i < objs.length; i++) {
    System.out.println(objs[i]);
  }
  //清空集合:clear()
  al.clear();
  System.out.println(al.size());
  System.out.println(al.isEmpty());

        (3)ArrayList集合因为可以使用索引来直接获取元素,所以其优点是遍历元素和随机访问元素的效率比较高。但是由于ArrayList集合采用了和数组相同的存储方式,在内存中分配连续的空间,因此在添加和删除非尾部元素时会导致后面所有元素的移动,这就造成在插入元素、删除元素等操作频繁的应用场景下使用ArrayList会导致性能低下。所以数据操作频繁时,最好使用LinkedList存储数据。

2、 使用LinkedList类动态存储数据

       (1)LinkedList类是List接口的链接列表实现类。它支持实现所有List接口可选的的列表的操作,并且允许元素值是任何数据,包括null。


       (2)LinkedList类采用链表存储方式存储数据,如下图所示,优点在于插入、删除元素时效率比较高,但是LinkedList类的查找效率很低。



1.gif

       (3)它除了包含ArrayList类所包含的方法之外,还提供了下表所示的一些方法,可以在LinkedList类的首部或尾部进行插入、删除操作。

//获取集合中的第一个元素
  Object obj2=linkList.getFirst();
  NewsTitle ntt2 = (NewsTitle)obj2;
  System.out.println(ntt2);
  //获取集合中的最后一个元素
  Object obj3=linkList.getLast();
  NewsTitle ntt3 = (NewsTitle)obj3;
  System.out.println(ntt3);
  //删除集合中的第一个元素和最后一个元素
  System.out.println("删除的第一个元素是:"+linkList.removeFirst());
  System.out.println("删除的最后一个元素是:"+linkList.removeLast());
  System.out.println("集合为空:"+linkList.isEmpty());
  linkList.clear();
  System.out.println("集合为空:"+linkList.isEmpty());

       (4)除了LinkedList类中特有的方法外,LinkedList类和ArrayList类所包含的大部分方法是完全一样的,这主要是因为它们都是List接口的实现类。由于ArrayList采用和数组一样的连续的顺序存储方式,当对数据频繁检索时效率较高,而LinkedList类采用链表存储方式,当对数据添加、删除或修改比较多时,建议选择LinkedList类存储数据。

三、Set接口


1、 Set接口概述

       (1)Set接口是Collection接口的另外一个常用子接口,Set接口描述的是一种比较简单的集合。


       (2)集合中的对象并不按特定的方式排序,并且不能保存重复的对象,也就是说Set接口可以存储一组唯一、无序的对象。


       (3)Set接口常用的实现类有HashSet。

2、 使用HashSet类动态存储数据


       (1)HashSet集合的特点如下:


               -->集合内的元素是无序排列的。


               -->HashSet类是非线程安全的。


               -->允许集合元素值为null。


       (2)HashSet类的常用方法如下所示:


1.gif


       (3)List接口可以使用for循环、增强for循环、迭代器(Iterator接口)三种方式遍历。使用for循环遍历时,通过get()方法取出每个对象,但HashSet类不存在get()方法,所以Set接口无法使用普通for循环遍历。


       (4)Set接口可以使用增强for循环、迭代器(Iterator接口)两种方式遍历。


        代码展示:


package cn.bdqn.demo03;
import java.util.HashSet;
import java.util.Iterator;
import cn.bdqn.demo02.NewsTitle;
public class HashSetDemo01 {
  public static void main(String[] args) {
  // 创建3个NewsTitle类对象
  NewsTitle nt1 = new NewsTitle(1001, "新闻1","作者1");
  NewsTitle nt2 = new NewsTitle(1002, "新闻2","作者2");
  NewsTitle nt3 = new NewsTitle(1003, "新闻3","作者3");
  // 数据准备好了,接下来要准备一个集合容器,使用
  HashSet hs = new HashSet();
  //将元素存储到集合中
  hs.add(nt1);
  hs.add(nt2);
  hs.add(nt3);
  hs.add(nt2);
  //获取集合中元素个数
  int size = hs.size();
  System.out.println("集合元素个数:"+size);
  //获取集合中的元素,Set集合是无序的,所以里面没有get(下标)方法获取元素
  for(Object object:hs){
    NewsTitle newsTitle = (NewsTitle)object;
    System.out.println(newsTitle);
  }
  System.out.println("--------------------使用迭代器遍历集合----------------");
  //可以通过迭代器来遍历元素
  Iterator it =hs.iterator();
  while(it.hasNext()){
    Object object = it.next();
    NewsTitle newsTitle = (NewsTitle)object;
    System.out.println(newsTitle);
  }
  }
}


四、Iterator接口


1、 Iterator接口概述

       (1)Iterator接口表示对集合进行迭代的迭代器。Iterator接口为集合而生,专门实现集合的遍历。


       (2)凡是由于Collection接口派生而来的接口或者类,都实现了iterator()方法,iterator()方法返回一个Iterator对象。


       (3)Iterator接口主要有如下两个方法:


               -->hasNext():判断是否存在在一个可访问的元素,如果仍有元素可以迭代,则返回true。


               -->next():返回要访问的下一个元素。

2、 使用Iterator遍历集合

Iterator it = list.iterator(); //获取集合迭代器Iterator
while(it.hashNext()){ //通过迭代器依次输出集合中所有元素的信息
    Object obj = it.next();
}

五、Map接口


1、 Map接口概述

(1)Map接口存储一组成对的键(key)——值(value)对象,提供key到value的映射,通过key来检索。


(2)Map接口中的key不要求有序,不允许重复。value同样不要求有序,但允许重复。


(3)Map接口的常用方法如下:


1.gif

2、使用HashMap类动态存储数据

(1)Map接口中存储的数据都是键——值对,最常用的Map的实现类是HashMap,其优点是查询元素效率高。


(2)遍历HashMap集合时可以遍历键集和值集,有for循环遍历、增强for循环遍历和迭代器(Iterator接口)遍历三种方式。


       代码展示:


(3)map集合的第3种遍历方式:map.entrySet()方法

//map集合的第3种遍历方式
  Set keyValues=map.entrySet();
  for(Object obje:keyValues){
    Map.Entry me =(Map.Entry)obje;
    //获取键
    Object ob1 = me.getKey();
    String key = (String)ob1;
    //获取值
    Object ob2 =me.getValue();
    Student student = (Student)ob2;
    System.out.println(key+"对应的学生:"+student);
  }
相关文章
|
24天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
36 6
|
24天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
34 3
|
24天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
31 2
|
26天前
|
存储 算法 Java
Java Set因其“无重复”特性在集合框架中独树一帜
【10月更文挑战第14天】Java Set因其“无重复”特性在集合框架中独树一帜。本文深入解析Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定的数据结构(哈希表、红黑树)确保元素唯一性,并提供最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的`hashCode()`与`equals()`方法。
27 3
|
4天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
11 2
|
4天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
9天前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
9天前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
9天前
|
Java 开发者
|
21天前
|
安全 Java 程序员
深入Java集合框架:解密List的Fail-Fast与Fail-Safe机制
本文介绍了 Java 中 List 的遍历和删除操作,重点讨论了快速失败(fail-fast)和安全失败(fail-safe)机制。通过普通 for 循环、迭代器和 foreach 循环的对比,详细解释了各种方法的优缺点及适用场景,特别是在多线程环境下的表现。最后推荐了适合高并发场景的 fail-safe 容器,如 CopyOnWriteArrayList 和 ConcurrentHashMap。
48 5