Java中集合的总结


集合

  • Java中的集合是工具类,可以存储任意数量的共同属性的数据。
  • 数组只能用于存储固定长度数据的场景,而集合可以存储任意长度的数据

集合的应用场景

  • 无法预测存储数据的数量
  • 同时存储具有一对一关系的数据
  • 需要进行数据的增删
  • 数据重复问题

集合的体系架构

  • Collection存储类的对象,例如,学生类的信息;Map主要是以键值对的形式存储信息,例如商品和商品的价格。
  • ListQueueSet是三个子接口。ListQueue是有序和允许重复的;Set是无序的且不可重复的。
  • ArrayListLinkedListHashSet是三个实现类,实现了三个对应的接口。
  • Map的主要实现类是HashMap

集合框架的体系结构示意图

List(列表)

  • List是元素有序并且可以重复的集合,称为序列;
  • List可以精确地控制每一个元素的插入位置,或删除某个位置的元素;
  • List的两个主要实现类是ArrayListLinkedList

ArrayList

  • ArrayList底层是由数组实现的;
  • 元素有序且可以重复;
  • 动态增长,以满足应用程序的需求;
  • 在列表尾部插入或删除数据非常有效;
  • 更适合查找和更新元素;
  • ArrayList中的元素可以为null

关于接口引用指向实现类对象的说明

  • 这实际上是一种多态的思想。多态的定义:指的是允许不同类的对象对同一个消息做出响应,即同一个消息可以根据发送对象的不同而采取多种不同的行为方式。(发送消息就是函数调用);
  • List list是在栈区开辟一个空间放list的引用,并没有创建对象所以不知道真正的对象是ArrayList还是LinkedList。当list = new ArrayList();的时候就创建了ArrayList对象,并且把开始创建的list引用指向这个对象。需要强调,ArrayListLinkedList都是List的实现类;
  • 那么为什么一般都使用List list = new ArrayList();而不用ArrayList list = new ArrayList();呢?因为List这个接口有多个实现类,如LinkedList或者Vector等等,现在你用的是ArrayList实现类,有可能之后需求更改需要使用其他的实现类了。如果使用的是前一种方法,那么只需要改变一开始的引用赋值的那一行代码就可以了,其他使用到list对象的代码根本不需要改动。假设如果你一开始就是用了第二种方法,尤其是你还是用了ArrayList这个实现类特有的方法,那么就需要更改非常多的代码,对程序的重构是没有好处的。因此,一般没有特别需求的情况下,使用List list = new ArrayList();是比较方便程序代码的重构的,这就是所谓的面向接口编程的好处。注意:如果采用了List list = new ArrayList();的方法创建实例对象,那么ArrayList这个实现类自己特有的方法是不可以被访问到的;
  • 接口的灵活性就在于“规定了一个类必须做什么,而不管你如何做”。我们可以定义一个接口类型的实例,当引用调用方法时,它会根据实际引用的类的实例来判断具体调用哪个方法,这和超类对象引用访问子类对象的机制是类似的。

Set&HashSet

  • 元素无序且不可以重复的集合,被称为集;
  • HashSetSet的一个重要实现类,称为哈希集;
  • HashSet中的元素无序且不可以重复;
  • HashSet只允许一个null元素;
  • 具有良好的存取和查找性能。

Iterator(迭代器)

  • Iterator接口可以以统一的方式对各种集合元素进行遍历;
  • hasNext()方法检测集合中是否还有下一个元素;
  • next()方法返回集合中的下一个元素。
  • 集合在进行遍历的时候是不允许进行元素的添加和删除的,如果要添加和删除需要在迭代循环的时候删除元素之后退出循环。
  • 使用迭代器遍历元素的示例代码如下:
Iterator it= set.iterator();
while(it.hasNext()){    //判断是否还有下一个元素
    System.out.print(it.next()+" ");   //it.next()代表了下一个元素
}

hashCode()equal()方法的重写

  • 重写这两个方法主要用在Hash相关的集合中,主要定义hash码的产生方式以及如何判定对象是否相等,重写这个方法可以定制Set的判定相等模式。
  • 以下代码为上述两个方法重写的示例,在IDEAJ中可以通过自动插入方式自动编写这两个方法。
@Override
public boolean equals(Object o) {
    //判断对象是否相等,相等则返回true,不用继续比较属性了
    if(this==o)
        return true;
    //判断obj是否是Cat类的对象
    if(o.getClass()==Cat.class){
        Cat cat=(Cat)o;
        return cat.getName().equals(this.getName())
                &&cat.getMonth()==this.getMonth()
                &&cat.getSpecies().equals(this.getSpecies());
    }
    else
        return false;
}

@Override
public int hashCode() {
    return Objects.hash(name, month, species);
}

泛型的概念

  • JavaSE 5.0之后引入的概念;
  • 利用对Object类型的引用实现参数类型的任意化,任意化的缺点就是要做显式的类型转换,这对于后期维护代码和修改代码来说带来了比较大的工作量。并且制定类型还会产生运行时错误,这是我们不希望看到的。使用泛型,就可以独立于特定数据类型来一次性定义算法,然后把算法应用于各种数据类型,而不需要做额外的工作。因此Java中定义了泛型的概念。
  • Java中泛型的概念和C++中模板的区别:C++为每一种数据类型都构建了底层代码,而Java只构建了一份代码,当需要另一种类型时,Java会重新构建代码。所以C++模板的代码体积比较大,但是由于代码已经全部构建好了,因此C++的执行速度更快。
  • 泛型的写法
Set<Cat> set = new HashSet<Cat>();
Iterator<Cat> it = set.iterator();

Map

  • Map中的数据是以键值对(key-value)的形式存储的;
  • key-value是以Entry类型的对象实例存在的,Entry是接口类;
  • 可以通过key值快速查找value
  • 一个映射不能包含重复的键
  • 每个键最多只能映射到一个值

HashMap

  • 基于哈希表的Map接口的实现;
  • 允许使用null值和null键,一个Map中只能有一个null键;
  • key值不允许重复;
  • HashMap中的Entry对象是无序排列的。

增强型for循环的使用

  • 我们也可以用增强型for循环来代替迭代器去遍历集合。
for(String str:set){
    if(str.equals("你好"))
        System.out.println("已经找到的对应的字符串");
}

文章作者: 南航古惑仔
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 南航古惑仔 !
  目录