list大于1对应的索引_list大于1对应的索引


List接口

1. List接口介绍

java.util.List接口继承自Collection接口, 是==单列集合==的一个重要分支, 习惯性的会将实现了List接口的对象称为List集合. 在List集合中允许出现重复的元素, 所有的元素是以一种线性方式进行储存的, 在程序中可以通过索引来访问集合中的指定元素. 另外, List集合还有一个特点就是==元素有序==, 即元素的存入顺序和取出顺序一致.

所以, List接口的特点 :

  1. 有序, 他是一个元素存取有序的集合, 例如, 存元素的顺序是11, 22, 33.那么集合中, 元素的储存就是按照11, 22, 33的顺序完成的.
  2. 有索引, 他是一个带有索引的集合, 通过索引就可以精确的操作集合中的元素 (与数组的索引是一个道理)
  3. 可重复, 集合中可以有重复的元素, 通过元素的equals方法, 来比较是否为重复的元素.

ArrayList类是List接口的实现类, 该类中的方法都来自与List中定义

2. List接口常用的方法

List作为Collection集合的子接口, 不但继承了Collection接口中的全部方法, 还增加了一些根据元素索引来操作集合的特有方法. 如下 :

  • public void add(int index, E element): 将指定的元素, 添加到该集合中的指定位置上.
  • E element代表 泛型元素, 即任何数据类型的元素
  • public E get(int index): 返回集合中指定位置的元素
  • public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素
  • public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素
  • public E set(int index, E element): 将指定的元素替换集合中指定位置的元素, 返回值是更新前的元素

List集合的特有的方法都是跟索引有关.

我们之前学习Collection体系的时候, 发现List集合下有很多的集合, 他们储存结构不同, 这样就导致了这些集合他们有各自的特点, 供我们在不同环境下使用.

3. ArrayList 集合

java.util.ArrayList集合数据存储的结构是数组结构, 元素增删慢, 查找快, 由于日常开发中使用最多的功能为查询数据, 遍历数据, 所以ArrayList是最常用的集合.

许多程序员开发时非常随意的使用ArrayList完成任何需求, 并不严谨, 这种用法是不提倡的.

4. LinkedList集合

java.util.LinkedList集合数据储存的结构是链表结构, 方便元素添减, 删除的集合

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。

这些方法我们作为了解即可:

  • public void addFirst(E e):将指定元素插入此列表的开头。
  • public void addLast(E e):将指定元素添加到此列表的结尾。
  • public E getFirst():返回此列表的第一个元素。
  • public E getLast():返回此列表的最后一个元素。
  • public E removeFirst():移除并返回此列表的第一个元素。
  • public E removeLast():移除并返回此列表的最后一个元素。
  • public E pop():从此列表所表示的堆栈处弹出一个元素。
  • public void push(E e):将元素推入此列表所表示的堆栈。
  • public boolean isEmpty():如果列表不包含元素,则返回true。LinkedList是List的子类,List中的方法LinkedList都是可以使用,这里就不做详细介绍,我们只需要了解LinkedList 的特有方法即可。在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。

Set 接口

Set是Collection下面的另一个子接口。Set接口有以下特点:

  1. 无序。(按照什么顺序存,不一定按照什么顺序取)
  2. 无索引。(不能根据索引获取元素)
  3. 不可重复(不能存放重复元素)Set是一个接口,如果要用,需要使用实现类,最常用的实现类是HashSet

哈希(Hash)值就是一个int数字, 我么你可以把哈希值看成对象的一个标识, 一个特征码.

在Object中有一个方法叫做hashCode, 可以获取对象的哈希值

  • int hashCode(): 获取对象的哈希值, 是Object类中的, 任意对象都可调用.
public class Student {
    private String name;
    private int age;
    //get set 方法
}

public class StudentTest {
    public static void main(String[] args) {
        Student stu = new Student("张三丰", 100);
        System.out.println(stu.hashCode());
        //1163157884
        //不new新对象, 改变stu的内容, hashCode怎么变?
        //hashCode不变

        Student stu2 = new Student("张三丰", 100);
        System.out.println(stu.hashCode());
        //1965725890

    }
}


Object类中的哈希值计算规则是根据地址值计算的, stustu2地址值不一样, 所以他们的哈希值是不相同的. 哈希值如果通过地址值计算的话, 意义不大.

我们大多数是希望根据对象的属性计算对象的哈希值, 如果两个对象的属性完全相同, 那么对象的哈希值也应该相同.

对象的哈希值是允许重复的.

如果要自己定义哈希值的计算规则, 比如根据对象的属性计算哈希值, 我们需要重写hashCode方法.

//重新对应哈希值的计算规则, 如果两个对象的属性值一样, 哈希值也相同.


@Override
public int hashCode() {
    return name.hashCode() + age;
}


小结:

  1. 哈希值是一个int数字
  2. 我们可以将哈希值看成对象的标识,特征码。
  3. 对象的哈希值允许重复。
  4. 调用hashCode方法可以获取对象的哈希值。
  5. 如果要自定义哈希值的计算规则,可以重写hashCode方法。

可以用快捷键alt + insert重写hashCodeequals方法

hashSet判断唯一性的过程

  1. 先比较两个对象的哈希值(调用hashCode方法)
    如果哈希值不同, 肯定是不同的对象
    如果哈希值相同, 不一定是同一个对象
  2. 如果哈希值相同, 那么还需要使用equals方法
    如果equals方法的结果是true, 那么两个对象相同
    如果equals方法的结果是false, 那么两个对象不同

java.util.Set接口和java.util.List接口一样, 同样继承自Collection接口, 他与Collection接口中的方法基本一致, 并没有功能上的扩充, 只是比Collection接口更加严格了. Set接口都会以某种规则保证存入的元素不出现重复.

Set集合有多个子类, 这里我们介绍其中的java.util.HashSet, java.util.LinkedHashSet这两个集合.

因为Set接口的无序性, 所以遍历的方式可以采用迭代器, 增强for

HashSet是根据对象的哈希值来确定元素在集合中的储存位置, 因此具有良好的储存和查找性能, 保证元素唯一性的方式依赖于: hashCodeequals方法.

先来一段使用案例:


public class HashSetTest {
    public static void main(String[] argsr) {
        HashSet <String> set = new HashSet<>();

        set.add(new String ("cba"));
        set.add("abc");
        set.add("bac");
        set.add("cba");

        for (String name : set) {
            System.out.println(name);
        }      
    }
}

//输出结果
//cba
//abc
//bac
//cba字符串只储存了一个, 说明重复的元素set集合不储存


1. HashSet集合存储数据的结构

首先要来了解一下什么是哈希表

JDK8之前, 哈希表底层采用数组加链表实现, 即使用数组处理冲突, 同一hash值的链表都储存在同一个数组里, 但是位于一个桶中的元素较多, 即hash值相等的元素较多时, 通过key值依次查找的效率较低.

而在JDK8中, 哈希表存储采用数组加链表加红黑树实现的,


总而言之, JDK8引入红黑树大程度优化了HashMap的性能, 那么对于我们来讲, HashSet集合元素的唯一, 其实是根据对象的hashCode和equals方法来决定的. 如果我们往集合中存放自定义的对象, 那么保证其唯一, 就必须重写hashCodeequals方法建立属于当前对象的比较方式.

2. HashSet储存自定义类型元素

HashSet中存放自定义类型的元素时, 需要重写对象中的hashCode和equals方法, 建立自己的比较方式, 才能保证HashSet集合中的对象唯一

代码演示 :


//自定义Student类
public class Student {
    private String name ;
    private int age;

    //get / set 方法

   @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }        
}


创建测试类 :


public class HashSetTest {
    public static void main(String[] args) {
        HashSet<Student> stuSet = new HashSet<Student>();

        Student stu  = new Student("于谦", 43);
        stuSet.add(stu);
        stuSet.add(new Student("郭德纲", 44);
        stuSet.add(new Student("于谦", 43));
        stuSet.add(new Student("郭麒麟", 23));
        stuSet.add(stu);

        for(Student stu2 : stuSet) {
            System.out.println(stu2);
        }
    }
}

//执行结果: 
Student [name=郭德纲, age=44]
Student [name=于谦, age=43]
Student [name=郭麒麟, age=23]


3. LinkedHashSet

我们知道HashSet保证元素唯一, 可是元素存放进去是没有顺序的, 那么我们要保证有序, 怎么办呢~

HashSet下面有一个子类java.util.LinkedHashSet, 它是链表和哈希值组合的一个数据储存结构

演示代码如下 :


package drafts.drafts2;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetTest    {
    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<>();
        set.add("bbb");
        set.add("aaa");
        set.add("abc");
        set.add("bbc");
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}