List、Set接口及两者选择

List接口

List:有序,可重复

  • ArrayList
    优点: 底层数据结构是数组,查询快,增删慢。
    缺点: 线程不安全,效率高
  • Vector
    优点: 底层数据结构是数组,查询快,增删慢。
    缺点: 线程安全,效率低
  • LinkedList
    优点: 底层数据结构是链表,查询慢,增删快。
    缺点: 线程不安全,效率高

List继承Collection,因此可以实现Collection的方法,这里只对List的特有功能进行举例使用

List
  • void add(int index,E element): 在指定索引处添加元素
public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add(3);
        list.add(1,2);
        System.out.println(list);
    }
}

输出结果

[1, 2, 3]
  • E remove(int index):移除指定索引处的元素 返回的是移除的元素
public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add(3);
        list.add(2);
        Object remove = list.remove(1);
        System.out.println(remove);
        System.out.println(list);
    }
}

输出结果

3
[1, 2]
  • E get(int index):获取指定索引处的元素
public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(10);
        list.add(20);
        list.add(30);
        Object o = list.get(1);
        System.out.println(o);
    }
}

输出结果

20
  • E set(int index,E element):更改指定索引处的元素 返回的而是被替换的元素
public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(10);
        list.add(30);
        list.add(30);
        Object o = list.set(1,20);
        System.out.println(o);
        System.out.println(list);
    }
}

输出结果

30
[10, 20, 30]
  • int indexOf(Object o):返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1
public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(10);
        list.add(20);
        list.add(30);
        int index = list.indexOf(30);
        int index1 = list.indexOf(1);
        System.out.println(index);
        System.out.println(index1);
    }
}

输出结果

2
-1
  • List subList(int fromIndex, int toIndex):返回从索引fromIndex到toIndex的元素集合,包左不包右
public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        List list1 = new ArrayList();
        list.add(10);
        list.add(20);
        list.add("a");
        list.add("b");
        list.add(30);
        list1 = list.subList(2, 4);
        System.out.println(list1);
    }
}

输出结果

[a, b]
  • ListIterator

    List特有的迭代器,和Iterator功能都一样,但是listIterator迭代器只能用于List和他的实现子类,Iterator迭代器可以用于所有的集合使用

  • listIterator迭代器可以在遍历集合时,添加、修改和删除,而Iterator迭代器在遍历集合时只有删除

public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        List list1 = new ArrayList();
        list.add(10);
        list.add(20);
        list.add(30);
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()) {
            Object next = listIterator.next();
            System.out.println(next);
        }
    }
}

输出结果

10
20
30
  • boolean hasPrevious(): 是否存在前一个元素
    E previous(): 返回列表中的前一个元素

用此方法可以实现反向遍历,但是反向遍历之前,需要进行正向遍历,这样指针才能移到最后

如果直接反向遍历,指针的默认位置是在最前面,会判断前面没有元素,从而无法遍历

public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        List list1 = new ArrayList();
        list.add(10);
        list.add(20);
        list.add(30);
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()) {
            Object next = listIterator.next();
            System.out.println(next);
        }
        System.out.println("-------------------------------------");	
        while (listIterator.hasPrevious()) {
            Object previous = listIterator.previous();
            System.out.println(previous);
        }
    }
}

输出结果

10
20
30
-------------------------------------
30
20
10

在JDK1.8之后,新增了遍历集合的方法

  • void forEach(Consumer<? super E> action) 执行特定动作的每一个元素的 Iterable直到所有元素都被处理或操作抛出异常
public class Test {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(10);
        list.add(20);
        list.add(30);
        list.forEach(new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println(o);
            }
        });
    }
}

输出结果

10
20
30

ArrayList,Vector,LinkedList皆有特有方法,查看API使用

Set接口

set:无序,唯一

  • HashSet
    底层数据结构是哈希表。(无序,唯一)(JDK1.7 数组+链表 JDK1.8 优化 数组+链表+红黑树)
    如何来保证元素唯一性?
    通过重写两个方法:hashCode()和equals()
  • LinkedHashSet
    底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
    1.由链表保证元素有序
    2.由哈希表保证元素唯一
  • TreeSet
    底层数据结构是红黑树。(唯一,有序)
    \1. 如何保证元素排序的呢?
    自然排序
    比较器排序
    2.如何保证元素唯一性的呢?
    根据比较的返回值是否是0来决定
HashSet
public class Test {
    public static void main(String[] args) {
        HashSet<Integer> Hs = new HashSet<>();
        Hs.add(100);
        Hs.add(10);
        Hs.add(20);
        Hs.add(20);
        Hs.add(40);
        Hs.add(30);
        for (Integer integer : Hs) {
            System.out.println(integer);
        }
    }
}

输出结果

100
20
40
10
30

我们发现输出的结果我们的输入的顺序不一致

LinkedHashSet
public class Test {
    public static void main(String[] args) {
        LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add(100);
        linkedHashSet.add(10);
        linkedHashSet.add(20);
        linkedHashSet.add(20);
        linkedHashSet.add(40);
        linkedHashSet.add(30);
        for (Integer integer : linkedHashSet) {
            System.out.println(integer);
        }
    }
}

输出结果

100
10
20
40
30

输出的结果和我们输入的顺序一致

TreeSet
TreeSet的自然排序
  • 使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素
    必须实现Comparable接口 否则无法进行自然排序
public class Test {
    public static void main(String[] args) {
        TreeSet<Student> treeSet = new TreeSet<>();
        treeSet.add(new Student("www",17));
        treeSet.add(new Student("yyy",18));
        treeSet.add(new Student("fff",16));
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}
public class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String
    toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student s) {
        int a=this.age-s.age;
        return a;
    }
}

输出结果

Student{name='fff', age=16}
Student{name='www', age=17}
Student{name='yyy', age=18}
TreeSet的比较器排序
public class Test {
    public static void main(String[] args) {
    	//采用匿名内部类
        TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int a=s1.getAge()-s2.getAge();
                return a;
            }
        });
        treeSet.add(new Student("www",17));
        treeSet.add(new Student("yyy",18));
        treeSet.add(new Student("fff",16));
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}

输出结果

Student{name='fff', age=16}
Student{name='www', age=17}
Student{name='yyy', age=18}

三者的异同

  • TreeSet, LinkedHashSet and HashSet 在java中都是实现Set的数据结构
  • TreeSet的主要功能用于排序
  • LinkedHashSet的主要功能用于保证FIFO即有序的集合(先进先出)
  • HashSet只是通用的存储数据的集合
相同点
  • Duplicates elements: 因为三者都实现Set interface,所以三者都不包含duplicate elements
  • Thread safety: 三者都不是线程安全的,如果要使用线程安全可以Collections.synchronizedSet()
不同点
  • HashSet插入数据最快,其次LinkHashSet,最慢的是TreeSet因为内部实现排序

两者的选择

唯一吗?

是:Set

排序吗?

是:TreeSet或LinkedHashSet
否:HashSet
如果你知道是Set,但是不知道是哪个Set,就用HashSet

否:List

要安全吗?

是:Vector
否:ArrayList或者LinkedList

查询多:ArrayList
增删多:LinkedList
如果你知道是List,但是不知道是哪个List,就用ArrayList

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值