Java集合框架详述之(Collection,List,Set)

有时候,不是因为你没有能力,也不是因为你缺少勇气,只是因为你付出的努力还太少,所以,成功便不会走向你。而你所需要做的,就是坚定你的梦想,你的目标,你的未来,然后以不达目的誓不罢休的那股劲,去付出你的努力,成功就会慢慢向你靠近。

导读:本篇文章讲解 Java集合框架详述之(Collection,List,Set),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

前言

Collection接口的层次结构图:

在这里插入图片描述

一、集合概述

所有的集合类和集合接口都在java.util包下。

  • 集合实际上就是一个容器。可以来容纳其它类型的数据,可以一次容纳多个对象。(数组其实就是一个集合。)

  • 集合不能直接存储基本数据类型,也不能直接存储java对象,集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)
    在这里插入图片描述

  • 在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,等于将数据放到了不同的数据结构当中。(例如:数组、二叉树、链表、哈希表…以上这些都是常见的数据结构。)

  • 在java中集合分为两大类:

一类是单个方式存储元素:
单个方式存储元素,这一类集合中超级父接口:java.util.Collection;
一类是以键值对儿的方式存储元素
以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;

二、Collection详述

Collection 是 List 和 Set 的父接口

Collection接口中的常用方法:

  • boolean add(E e) 向集合中添加元素
  • int size();获取集合中的元素个数
  • void clear();清空集合
  • boolean contains(Object o) 判断当前集合是否含有o元素
  • boolean remove(Object o) 删除集合中的元素
  • boolean isEmpty() 判断集合是否为空
  • Object[] toArray() 把集合转换为数组

示例代码(1):

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

public class CollectionText {
    public static void main(String[] args) {
        
        Collection collection = new ArrayList();
        //向集合中添加元素
        boolean b1 = collection.add(100);
        boolean b2 = collection.add("你好,java");
        boolean b3 = collection.add("中国");
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b3);
        //获取集合中的元素个数
        int i1 = collection.size();
        System.out.println(i1);

        //collection.clear();
        //System.out.println(collection.size());

        boolean b = collection.contains(100);
        System.out.println(b);
          //删除集合中的元素
        collection.remove("中国");
        System.out.println(collection.size());
         //判断集合是否为空
        System.out.println(collection.isEmpty());
        collection.clear();
        System.out.println(collection.isEmpty());

        collection.add("我");
        collection.add("是");
        collection.add("中");
        collection.add("国");
        collection.add("人");
        //转换为数组
        Object[] objects=collection.toArray();
        for(int i=0;i<objects.length;i++){
            Object o=objects[i];
            System.out.println(o);
        }
        System.out.println(Arrays.toString(objects));
    }
}

运行结果:

true
true
true
3
true
2
false
true
我
是
中
国
人
[,,,,]

Process finished with exit code 0

注:Collection在使用泛型之前,可存放Object的所有子类,在使用泛型之后,只能存某个具体的类型。

集合的迭代(遍历)

迭代器是一个对象

  • 所有Collection以及子类通用,Map集合不能使用。
  • 使用迭代器的步骤:

第一步:获取集合对象的迭代器对象
第二部:通过获取的迭代器对象进行迭代(遍历)

  • 迭代器(iterator)中的方法:

boolean hasNext(); true:有元素迭代 false:无元素迭代
E next() ;返回迭代的下一个元素

在这里插入图片描述
示例代码(2):

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionText01 {
    public static void main(String[] args) {
        //创建集合
        Collection c1=new ArrayList();
        c1.add(100);
        c1.add("abc");
        c1.add("def");
        c1.add(new Object());
        //第一步:获取集合对象的迭代器对象iterator
        Iterator it=c1.iterator();
        //第二步通过获取的迭代器对象进行集合遍历/迭代。
        while (it.hasNext()){
            Object obj=it.next();
            System.out.println(obj);
        }
    }
}

运行结果:

100
abc
def
java.lang.Object@723279cf
  • 迭代器重要规律:

1.集合结果发生改变,迭代器需要重新获取
2.迭代过程中不能调用remove()方法删除元素,会出现异常(ConcurrentModificationException)
3.迭代元素的过程中使用迭代器的remove()方法删除元素

示例代码(3):

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionText05 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        //ConcurrentModificationException异常!!!
        //Iterator it=c.iterator();

        c.add(1);
        c.add(2);
        c.add(3);
        Iterator it=c.iterator();
        while (it.hasNext()){
            Object o=it.next();
            // 没有更新迭代器
            //c.remove();直接通过集合,没有通知迭代器(导致迭代器快照与原集合状态不同)
            //更新迭代器 。
            it.remove(); //删除的是迭代器指向的当前对象。
            System.out.println(o);
        }
        System.out.println(c.size());
    }
}

运行结果:

1
2
3
0

三、List详述

  • List集合存储元素特点:有序,可重复!

他们都是有顺序的,也就是放进去是什么顺序,取出来还是什么顺序,也就是基于线性存储,可以看作是一个可变数组

  • List 接口下面主要有三个实现 ArrayList 、LinkedList和Vector

List接口的常用方法:

  • void add(int index, E element) 在列表中指定的位置上插入指定的元素
  • E get(int index) 根据下标获取元素
  • int indexOf(Object o) 返回此列表中指定元素的第一个出现的索引
  • int lastIndexOf(Object o) 返回此列表中指定元素的最后一个发生的索引
  • E remove(int index) 移除此列表中指定下标的元素
  • E set(int index, E element) 用指定元素替换此列表中指定位置的元素

示例代码(4):

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListText01 {
    public static void main(String[] args) {
        //创建list类型集合
        List list=new ArrayList();
        //添加元素,将指定的元素到这个列表的末尾
        list.add("a");
        list.add("b");
        list.add("c");

        //在列表中指定的位置上插入指定的元素(效率低!!!)
        list.add(1,"ooo");

        //迭代器
        Iterator it=list.iterator();
        while(it.hasNext()){
            Object o=it.next();
            System.out.println(o);
        }
        System.out.println("=================================");

        //根据下标获取元素
        Object o=list.get(0);
        System.out.println(o);

        //list集合特有的遍历方法!!
        for(int i=0;i<list.size();i++){
            System.out.println( list.get(i));
        }

        // 返回此列表中指定元素的第一个出现的索引
        System.out.println(list.indexOf("b"));
        //返回此列表中指定元素的最后一个发生的索引
        System.out.println(list.lastIndexOf("c"));

        System.out.println("=============================");

        //移除此列表中指定位置的元素
        list.remove(1);
        System.out.println(list.size());//3
        //用指定元素替换此列表中指定位置的元素
        list.set(0,"n");
        System.out.println(list.get(0));
    }
}

运行结果:

a
ooo
b
c
==============================
a
a
ooo
b
c
2
3
=============================
3
n

ArrayList类

  • ArrayList底层是Object类型的数组。
  • ArrayList集合初始化容量10。添加第一个元素时,创建长度为10的空数组。
  • 扩容机制:扩容为原容量1.5倍。

ArrayList集合优化:尽可能少的扩容,数组扩容效率低。

  • ArrayList集合优缺点:

优点:查询数据比较快,检索效率高
缺点:添加和删除数据比较慢,无法存大数据量(向数组末尾添加元素效率高)

  • ArrayList是非线程安全

示例代码(5):

import java.util.*;

public class ArrayListText01 {
    public static void main(String[] args) {
       //初始化容量为10
        List list1=new ArrayList();
        //初始化容量为20
        List  list2=new ArrayList(20);

        Collection c=new ArrayList();
        c.add("cccc");
        c.add("bvncm");
        c.add("mnkj");

        Iterator it=c.iterator();   
        while (it.hasNext()){
            Object o= it.next();
            System.out.println(o);
        }
    }
}

运行结果:

cccc
bvncm
mnkj

LinkedList类

  • LinkedList底层是基于链表数据结构。
  • LinkedList集合优缺点:

优点:添加和删除数据比较快,随机增删效率高
缺点:查询数据比较慢,检索效率低。

Vector类

  • Vector初始化容量是10.
  • 扩容为原容量的2倍。
  • Vector底层是数组。
  • Vector底层是线程安全的,但是效率低

泛型机制(jdk1.5之后新特性)

  • 只在编译时起作用,给编译器参考
  • 泛型优缺点:

优点:
1.集合中存储元素类型统一
2.集合中去除掉元素是泛型指定的类型,无需进行向下转型。
缺点:导致集合中元素缺乏多样性

  • JDK8新特性:钻石表达式
List<String> list = new ArrayList<>();
	类型自动推断!

示例代码(6):

使用泛型之前

自定义类:

class Animal{
    public void run(){
        System.out.println("动物在移动!!");
    }
}
class Cat extends Animal{
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

class Dog extends Animal{
    public void fly(){
        System.out.println("狗在飞");
    }
}

测试类:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * jdk5.0之后的特性:泛型
 */
public class GenericText {
    //使用泛型之前
    public static void main(String[] args) {
        List list = new ArrayList();

        Cat cat = new Cat();
        Dog dog = new Dog();

        list.add(cat);
        list.add(dog);

        Iterator it = list.iterator();

        while (it.hasNext()) {
            Object o = it.next();
            if (o instanceof Animal) {
                ((Animal) o).run();
            }
        }
    }
}

运行结果:

动物在移动!!
动物在移动!!

使用泛型之后

测试类:

public class GenericText {
    public static void main(String[] args) {
        //使用泛型List<Animal>后,表示List集合只能存储Animal类型的元素
        //泛型指定集合中存储的数据类型
        List<Animal> list = new ArrayList<Animal>();

        Cat cat = new Cat();
        Dog dog = new Dog();

        list.add(cat);
        list.add(dog);
        //表示迭代器迭代Animal类型
        Iterator<Animal> it = list.iterator();
        while (it.hasNext()) {
            //使用泛型后,迭代器每一次返回的数据是Animal类型
            Animal a = it.next();
            //无需强转,直接调用
            a.run();
            if (a instanceof Cat) {
                ((Cat) a).catchMouse();
            } else if (a instanceof Dog) {
                ((Dog) a).fly();
            }
        }
    }
}

运行结果:

动物在移动!!
猫抓老鼠
动物在移动!!
狗在飞

一起找不同吧!!!!!

四、Set详述

  • Set集合存储元素特点:无序不可重复。

无序表示存进去是这个顺序,取出来就不一定是这个顺序了,另外Set集合中元素没有下标。Set集合中的元素还不能重复。

HashSet类

HashSet 中的数据是无序的不可重复的。HashSet 按照哈希算法存取数据的,具有非常好性能,它的工作原理是这样的,当向 HashSet 中插入数据的时候,他会调用对象的 hashCode 得到该对象的哈希码,然后根据哈希码计算出该对象插入到集合中的位置。

  • HashSet不是同步的;
  • 集合元素值可以是null;

如果HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode方法来得到该对象的hashCode值,然后根据该hashCode值决定该对象在HashSet中的存储位置。如果有两个元素通过equals方法比较true,但它们的hashCode方法返回的值不相等,HashSet将会把它们存储在不同位置,依然可以添加成功。
HashSet集合判断两个元素的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等。

特别是向 HashSet 或 HashMap 中加入数据时必须同时覆盖 equals 和 hashCode 方法,应该养成一种习惯覆盖 equals 的同时最好同时覆盖 hashCode

  • Java语法要求:

两个对象 equals 相等,那么它的 hashcode 相等
两个对象 equals 不相等,那么它的 hashcode 并不要求它不相等,但一般建议不相等
hashcode 相等不代表两个对象相等(采用 equals 比较)

哈希表

  • 一个元素为链表的数组,综合了数组与链表的优点。

示例代码(7):

没有重写hashCode和equals之前

自定义类:

public class Student {
    private String name;

    public Student() {

    }

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

    public String getName() {
        return name;
    }

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

测试类:

import java.util.HashSet;
import java.util.Set;

public class HashMapText02 {
    public static void main(String[] args) {
        Student s1 = new Student("zhangsan");
        Student s2 = new Student("zhangsan");

        System.out.println(s1.equals(s2));
        //重写hashCode之前
        System.out.println("s1hashCode值:" + s1.hashCode());
        System.out.println("s2hashCode值:" + s2.hashCode());

        Set<Student> set=new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());//2
      }
}

运行结果:

false
s1hashCode值:284720968
s2hashCode值:122883338
2

重写hashCode和equals之后

自定义类:

public class Student {
    private String name;

    public Student() {

    }

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

    public String getName() {
        return name;
    }

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

    //equals方法
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
    }

    //hashCode方法
    public int hashCode() {
        return Objects.hash(name);
    }
}

测试类:

import java.util.HashSet;
import java.util.Set;

public class HashMapText02 {
    public static void main(String[] args) {
        Student s1 = new Student("zhangsan");
        Student s2 = new Student("zhangsan");

        System.out.println(s1.equals(s2));
        //重写hashCode之后
        System.out.println("s1hashCode值:" + s1.hashCode());
        System.out.println("s2hashCode值:" + s2.hashCode());

   Set<Student> set=new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());//1
    }
}

运行结果:

true
s1hashCode值:-1432604525
s2hashCode值:-1432604525
1

找呀找呀,找不同。

TreeSet类

  • TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
  • TreeSet 可以对 Set 集合进行排序,默认自然排序(即升序)
  • TreeSet 是可排序的
  • TreeSet集合对自定义数据可以排序方法:

第一种:Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接口的类必须实现该方法,实现接口的类就可以比较大小了。当调用一个一个对象调用该方法与另一个对象进行比较obj1.compareTo(obj2)如果返回0表示两个对象相等;如果返回正整数则表明obj1大于obj2,如果是负整数则相反。
第二种:在构造TreeSet或TreeMap集合时给他一个比较器对象。比较规则自己写!!!

  • Comparable 与Comparator区别?

当比较规则不会发生改变时或比较规则只用一个时建议实现Comparable接口
当比较规则有多个,并且需要多个比较规则之间进行切换,建议使用与Comparator
编写比较器可以改变规则!!!
Comparator区别符合OCT原则

红黑树(自平衡二叉树)

  • TreeSet内部实现的是红黑树,默认整形排序为从小到大。
  • 三种遍历方式:前序遍历,中序遍历,后序遍历。(前中后指的是根的位置)
  • TreeSet采用中序遍历方式。

在这里插入图片描述
在这里插入图片描述
示例代码(8):

import java.util.TreeSet;

public class TreeMapText01 {
    public static void main(String[] args) {
        //
        TreeSet<String> ts=new TreeSet();
        ts.add("zhangsan");
        ts.add("wangwu");
        ts.add("make");
        ts.add("langlang");
        for (String s: ts){
            System.out.println(s);
        }
        System.out.println("=============================");
        TreeSet<Integer> ts2=new TreeSet();
        ts2.add(200);
        ts2.add(300);
        ts2.add(600);
        ts2.add(14);
        for (Integer i:ts2){
            System.out.println(i);
        }
    }
}

运行结果:

langlang
make
wangwu
zhangsan
=============================
14
200
300
600

Process finished with exit code 0

从以上结果可以看出,String类和Integer类都实现了这个接口。
示例代码(9):

实现Comparable接口

Customer类:

class Customer implements Comparable<Customer>{
    int age;

    public Customer(int age) {
        this.age = age;
    }
    //需要在此方法写比较的逻辑,或者说出比较规则,按照什么进行比较!!
    //比较规则自己定

    public int compareTo(Customer o) {//c1.comperTo(c2);
        //this是c1,o是c2
        //c1与c2比较,就是this与c比较
       // return this.age-o.age;
        return o.age-this.age;
    }

    @Override
    public String toString() {
        return "Customer{" + "age=" + age + '}';
    }
}

测试类:

import java.util.TreeSet;

public class TreeSetText03 {
    public static void main(String[] args) {
        Customer p = new Customer(23);
        Customer p2 = new Customer(100);
        Customer p3 = new Customer(30);
        Customer p4 = new Customer(65);
        Customer p5 = new Customer(46);

        TreeSet<Customer> treeSet = new TreeSet<>();

        treeSet.add(p);
        treeSet.add(p2);
        treeSet.add(p3);
        treeSet.add(p4);
        treeSet.add(p5);
        for (Customer c : treeSet) {
            System.out.println(c);
        }
    }
}

运行结果:

Customer{age=100}
Customer{age=65}
Customer{age=46}
Customer{age=30}
Customer{age=23}

示例代码(10):

比较器进行排序

WuGui类:

class WuGui {
    int age;

    public WuGui(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "WuGui{" +
                "age=" + age +
                '}';
    }
}

比较器:

//单独在这里编写一个比较器
//比较实现java.util.Comparator接口。(Comparable是java.lang包下的,Comparator接口是java.util包下)

class WuguiComparator implements Comparator<WuGui> {

    public int compare(WuGui o1, WuGui o2) {
        return o1.age - o2.age;
    }
}

测试类:

import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetText05 {
    public static void main(String[] args) {
        //创建TreeSet时,需要使用比较器
        //TreeSet<WuGui> wuGuis=new TreeSet<>();这样不行,没有通过构造方法构造一个比较器进去
        //给构造方法添加一个比较器
        TreeSet<WuGui> wuGuis = new TreeSet<>(new WuguiComparator());
        wuGuis.add(new WuGui(200));
        wuGuis.add(new WuGui(30));
        wuGuis.add(new WuGui(50));
        wuGuis.add(new WuGui(10));
        wuGuis.add(new WuGui(100));

        for (WuGui w : wuGuis) {
            System.out.println(w);
        }
    }
}

运行结果:

WuGui{age=10}
WuGui{age=30}
WuGui{age=50}
WuGui{age=100}
WuGui{age=200}

改进上面测试类(使用匿名内部类)代码如下:

public class TreeSetText05 {
    public static void main(String[] args) {
  //第三种!! //使用匿名内部类的方式  这个类没有名字,直接new接口!!
        TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
            @Override
            public int compare(WuGui o1, WuGui o2) {
                return o1.age - o2.age;
            }
        });
        wuGuis.add(new WuGui(200));
        wuGuis.add(new WuGui(30));
        wuGuis.add(new WuGui(50));
        wuGuis.add(new WuGui(10));
        wuGuis.add(new WuGui(100));

        for (WuGui w : wuGuis) {
            System.out.println(w);
        }
    }
}

推荐阅读:

十三、Java异常处理机制详解(建议收藏保存)
先不要知道它是为什么,得先知道它能干什么!!!!!

你们的支持是我分享和进步的动力,一起加油,一起努力,一起秃见成效!!
今天的分享就到这里啦!!~感谢大家的观看,希望对大家有帮助的话麻烦给个丝滑三连击。(点赞+转发+关注)

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/144934.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!