数组和集合

数组和集合

数组的特点

  • 数组中保存的元素都是有序的,可以通过下标快速访问
  • 数组中保存的数据都是同一类型
  • 数组的长度在定义后,无法改变
  • 数组无法获取其中元素的实际数量

集合的特点

  • 能保存一组数据,可以有序也可以无序
  • 集合的容量可变
  • 集合中可以保存不同类型的数据
  • 可以获取集合中保存的元素实际数量

集合框架(集合家族)

Collection还有父接口Iterable,但Iterable接口不算严格意义上的集合的根接口。它称为迭代器,是用于遍历集合元素的一个工具接口。

所以集合的根接口为Collect接口和Map接口,位于java.util包中。

以上所有实现类都是非线程安全的,在多线程的环境下使用以上任意集合,都会产生不确定的效果。

Collection接口

该接口有两个核心子接口:List和Set。

这两个接口都可以保存一族元素,List接口保存元素时,是有序可重复的Set接口保存元素时,是无需不重复的

常用方法 返回值 作用
add(Object obj) boolean 将元素添加到集合中
size() int 获取集合中的元素数量
isEmpty() boolean 判断集合是否为空
clear() void 清空集合
contains(Object obj) boolean 判断集合中是否存在指定元素
remove(Object obj) boolean 移除集合中得指定元素
toArray Object[] 将集合转换为数组
Iterator() Iterator 获取集合的迭代器对象,用于遍历集合

List接口(有序可重复)

有序集合,元素可以重复,允许保存null,可以通过索引获取对应位置上的元素。

在该接口继承Collection接口的同时,又拓展了一些操作元素的方法,如添加到指定索引、根据索引删除、获取指定索引的元素、截取子集合的方法等。

常用方法 返回值 作用
get(int index) Object 根据指定索引获取对应元素
set(int index,Object obj) Object 使用obj替换index上的元素,返回被替换的元素
add(int index,Object obj) void 将obj添加到index上
remove(int index) Object 移除指定索引的元素
indexOf(Object obj) int 得到某元素第一次出现的索引,没有返回-1
lastIndexOf(Object obj) int 得到某元素最后一次出现的索引,没有返回-1
subList(int from,int to) List 截取[from,to)区间内的元素,返回子集合

ArrayList实现类(掌握)

  • 采用数组实现的集合
  • 可以通过索引访问元素,可以改变集合的大小,如果要往其中插入或删除元素时,会影响后续元素
  • 该集合中保存的都是引用类型,即便保存了数字123,也保存的是Integer类型的123,而不是int类型的123
  • 该集合查询效率高,中途增加和删除元素效率低
构造方法
常用构造方法 说明
ArrayList() 创建一个Object类型的空数组。在调用添加方法后,才会更改该数组大小为10
ArrayList(int initialCapacity) 创建一个指定容量的Object数组,如果参数为负,会抛出illegalArgumentException异常。
常用方法

ArrayList中的常用方法,就是Collection接口和List接口中的方法都有对应的实现。

LinkedList实现类
  • 采用双向链表实现的集合
  • 集合中保存的每个元素也称为节点,除了首尾节点外,其余节点都保存了自己的信息外,还保存了其前一个和后一个节点的地址
  • 如果在双向链表的数据结构中插入和删除操作节点时,不会影响其它节点的位置,如添加时,只需重新定义新节点的前后位置即可。
  • 如果要查询某个节点时,需要从头结点或尾结点开始一步步得到目标节点的位置
  • 双向链表在中间插入和删除的效率高,随机读取的效率低
构造方法
常用构造方法 说明
LinkedList() 创建一个空链表
常用方法

由于LinkedList既实现了List接口,有实现了Deque接口,所以还有Deque接口的一些方法。

实现Deque接口的方法 说明
addFirst(Object obj) 添加头元素
lastFirst(Object obj) 添加尾元素
removeFirst() 移除头元素
removeLast() 移除尾元素
getFirst() 得到头元素
getLast() 得到尾元素
remove() 移除头元素
pop() 移除头元素
push(Object obj) 添加头元素
peek() 得到头元素
poll() 移除头元素
offer(Object obj) 添加尾元素

ArrayList和LinkedList的区别

  • 这两个类都是List接口的实现类,保存的元素有序可重复,允许保存null。
  • ArrayList采用数组实现,随机读取效率高,插入删除效率低,适合用于查询。
  • LinkedList采用双向链表实现,插入删除时不影响其他元素,效率高,随机读取效率低,适合用于频繁更新集合。

Set接口(无序不重复)

无序集合,元素不可以重复,允许保存null,没有索引。

Set接口中没有自己定义的方法,都是继承于Collection接口中的方法

哈希表hash table

哈希表也称为散列表,是一种数据结构,能更快地访问数据。

要保存的数据称为原始值,这个原始值通过一个函数得到一个新的数据,这个函数称为哈希函数,这个新数据称为哈希码,哈希码与原始值之间有一个映射关系,这个关系称为哈希映射,可以构造一张映射表,这个表称为哈希表。在哈希表中,可以通过哈希码快速的访问对应的原始值。

假设原本的数据为左侧的数组。

如果要查询10,需要遍历数组,效率不高。

通过一个特定的函数“原始值%5”,得到一组新数据,让数据重新对应函数,保存到新数组中。

这是如果要查询10,由于哈希函数是通过%5得到了0,所以直接查询哈希表中0对应的元素即可。

整个过程中,这个函数称为哈希函数,得到的数据称为哈希函数,新数组为哈希表,对应关系为哈希映射。

这个哈希函数,有一定的几率让多个原始值得到相同的哈希码,这种情况称为哈希冲突(哈希码一致,实际值不同),

为了解决哈希冲突,可以使用“拉链法”,将2这个哈希码所在的位置像链表一样进行延伸。

哈希码的特点

  • 如果两个对象的hashCode不同,这两个对象一定不同
  • 如果两个对象的hashCode相同,这两个对象不一定相同
    • hashCode相同,对象不同,这种现象称为哈希冲突
    • **“通话""重地”**这两个字符串的hashCode相同,但不是同一个对象,称为哈希冲突

hashSet实现类

  • 采用哈希表实现
  • 元素不能重复,无序保存,允许保存一个null
  • 本质是一个HashMap对象
  • 再使用hashSet集合时,一般要重写hashCode()方法
构造方法
常用构造方法 说明
HashSet() 实际是创建一个HashMap对象
常用方法

HashSet中没有属于自定义的方法,都重写了父接口Set和Collection中的方法。这里参考Collection中的方法即可。

没有与索引相关的方法。

HashSet添加数据的原理

如果两个元素的HashCode相同,且equals结果为true,视为同一个对象,不能添加。

每次向集合中添加元素时,先判断该元素的hashCode是否存在

  • 如果不存在,视为不同对象,直接添加
  • 如果存在,再判断equals方法的结果
    • 如果false,视为不同对象,可以添加
    • 如果true,视为同一对象,不能添加

由此可见,不能添加的条件是两个对象的HashCode相同,且equals结果为true。

如果每次只判断equals的话,由于equals方法通常重写时会判断很多属性,效率不高。

如果每次只判断hashCode的话,可能会有哈希冲突。

所以先判断hashCode,再判断equals,既能保证效率,又能保证不添加重复元素

HashSet的应用

如果想要保存的对象不重复,且无关顺序,可以使用HashSet,如

Goods类

package day5.com.hqyj.hashSetTest;

import java.util.Objects;

/*
* 定义商品类
* 品牌、名称、价格
* */
public class Goods {
   
    private String brand;
    private String name;
    private int price;

    @Override
    public boolean equals(Object o) {
   
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Goods goods = (Goods) o;
        return price == goods.price &&
                Objects.equals(brand, goods.brand) &&
                Objects.equals(name, goods.name);
    }

    /*
    * 根据所有属性生成哈希码
    * 如果两个对象的所有属性都一致,生成的哈希码就一致
    * */
    @Override
    public int hashCode() {
   
        return Objects.hash(brand, name, price);
    }

    public Goods(String brand, String name, int price) {
   
        this.brand = brand;
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
   
        return "Goods{" +
                "brand='" + brand + '\'' +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    public String getBrand() {
   
        return brand;
    }

    public void setBrand(String brand) {
   
        this.brand = brand;
    }

    public String getName() {
   
        return name;
    }

    public void setName(String name) {
   
        this.name = name;
    }

    public int getPrice() {
   
        return price;
    }

    public void setPrice(int price) {
   
        this.price = price;
    }
}

Mian类

package day5.com.hqyj.hashSetTest;

import java.util.HashSet;
import java.util.Iterator;

public class Main {
   
    public static void main(String[] args) {
   
        //创建一个hashset集合
        HashSet<Goods> hs = new HashSet<>();
        //创建Goods对象
        Goods g1 = new Goods("康师傅", "冰红茶", 3);
        Goods g2 = new Goods("康师傅", "香辣牛肉面", 5);
        Goods g3 = new Goods("农夫山泉", "矿泉水", 2);
        Goods g4 = new Goods("农夫山泉", "矿泉水", 2);

        //第一次添加,一定可以添加
        hs.add(g1);
        //第二次添加,对象属性不同,hashCode不同,可以添加
        hs.add(g2);
        //第三次添加,对象属性不同,hashCode不同,可以添加
        hs.add(g3);
        //第四次添加,对象属性相同,hashCode相同,在判断equals结果,true,视为已存在,不能添加
        hs.add(g4);

        /*
        * hashSet没有可以通过索引获取对象的方法,所以无法使用普通for循环
        * 这里可以使用增强for循环
        * */
        for(Goods g : hs){
   
            System.out.println(g);
        }

        /*
        //可以使用迭代器遍历HashSet集合中的元素
        Iterator<Goods> it = hs.iterator();
        while (it.hasNext()){
            Goods goods =it.next();
            System.out.println(goods);
        }
         */
    }
}

equals方法和hashCode的关系
  • 如果两个对象的equals方法结果为true,在没有重写equals方法的前提下,hashCode相同。

    • 如果没有重写equals,默认是Object中使用==判断,如果结果为true说明是同一个对象,hashCode一定相同
    • </
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值