java集合

从501开始的

1.集合概述

  • 集合实际上就是一个容器,可以来容纳其他类型的数据。

    集合可以一次容纳多个对象,在实际开发中,假设要连接数据库,数据库当中有10条记录,要把这10条记录查询出来,这个过程中java程序会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。

  • 集合不能直接存储基本数据和java对象,集合中存储的是java对象的内存地址。(或者说集合中存储的是引用)

java集合_第1张图片

  • 在java中每一个不同的集合底层会对应不同的结构,往不同的集合中存储元素等于将数据放到了不同的数据结构中。

    数据结构就是数据存储的结构,如数组、二叉树、链表、哈希表等。

    new ArrayList(); 创建一个集合对象,底层是数组

    new LinkedList(); 创建一个集合对象,底层是链表

    new TreeSet(); 创建一个集合对象,底层是二叉树

  • 集合在Java.util.*; 所有的集合类和集合接口都在java.util下

  • java中集合分为两大类:

    • 一类是单个方式存储元素,超级父接口是java.util.Collection;
    • 一类是以键值对的形式存储元素,超级父接口是java.util.Map;

java集合_第2张图片

2.集合继承关系图

2.1 Collection集合

java集合_第3张图片

解释:首先迭代的意思就是遍历,把集合中的数据一个一个取出来。

  • 下面这三个接口的关系:
    • Iterable中有个方法叫iterator(),这个方法的作用是返回一个Iterator对象,也就是迭代器对象。即 Iterator it = “Collection对象”.iterator();拿到的it这个对象是用来迭代这个集合Collection的
    • 迭代器Iterator里面有三个方法分别为hasNext()、next()、remove()这三个方法,可以用于集合遍历。
    • Iterator和Collection是关联关系,不是继承关系。
    • 图中的泛化关系就是继承关系
    • Collection里面方法有很多,太多没写出来。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-90FaSSLL-1616397502354)(F:\学习笔记\学习笔记MD\JAVA学习\JAVApicture\集合\image-20210312161838084.png)]

  • 下面这两个接口的特点(并不是只有List和Set,主要掌握这两个)
    • List和Set接口继承了Collection接口
    • List集合存储元素的特点是有序可重复,存储的元素有下标。(可重复的意思是存储的数据可以重复)
    • Set集合无序不可重复

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OoTScPM5-1616397502357)(F:\学习笔记\学习笔记MD\JAVA学习\JAVApicture\集合\image-20210312163144575.png)]

  • List的实现类中三个比较重要
    • ArrayList、LinkedList、Vector是实现了List接口的类
    • ArrayList底层是数组
    • LinkedList底层是双向链表
    • Vector底层是数组

java集合_第4张图片

  • Set的实现类
    • HashSet集合底层实际上new了一个HashMap集合其底层是哈希表
    • SortedSet这个接口继承了Set接口,他的一个实现类是TreeSet
    • TreeSet集合底层实际上是TreeMap,new TreeSet集合的时候底层实际上new了一个TreeMap集合,数据放在了TreeMap集合中了。TreeMap底层采用了二叉树数据结构
    • SortedSet集合继承成了Set集合,也是无序不可重复,但是放在SortedSet集合中的元素是按照元素大小自动排序的。

java集合_第5张图片

2.2 Map集合

java集合_第6张图片

2.3 总结

ArrayList:底层是数组。放进去的值可以重复。

LinkedList:底层是双向链表。

Vector:底层是数组,线程安全的,效率较低,使用较少。

HashSet:底层是HashMap,放到HashSet集合的元素等同于放到HashMap集合的key部分。

TreeSet:底层是TreeMap,放到TreeSet集合的元素等同于放到TreeMap集合的key部分。

HashMap:底层是哈希表。

Hashtable:底层也是哈希表,线程安全的,效率较低,使用较少。

Properties:是线程安全的,并且key和value只能存储字符串String。

TreeMap:底层是二叉树,TreeMap集合的key可以自动按照大小顺序排序。

  • List集合存储元素的特点:

    ​ 有序可重复。

    ​ 有序:存进去的顺序和取出来的顺序相同,每一个元素都有下标。

    ​ 可重复:存进去一个1,可以再存进去一个1。

  • Set集合存储元素的特点:

    ​ 无序不可重复。

    ​ 无序:存进去的顺序和取出来的顺序不一定相同,另外每一个元素没有下标。

    ​ 不可重复:存进去一个1,不能再存储一个1。

  • SortedSet集合存储元素的特点:

    ​ 首先是无序不可重复的,但是SortedSet集合中的元素是可排序的。

    ​ 无序:存进去的顺序和取出来的顺序不一定相同,另外每一个元素没有下标。

    ​ 不可重复:例如存进去一个1,不能再存储一个1。

    ​ 可排序:可以按照大小进行排列。

往HashSet集合加数据:实际上是把数据加到Map集合里的key部分了

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

3. Collection中的常用方法

3.1 普通常用方法

关于java.util.Collection接口中常用的方法

  1. Collection中能存放的元素:
    没有使用“泛型”之前,Collection中可以存储Object的所有子类型。(注意只能存java对象的内存地址)
    使用了“泛型”之后,Collection中只能存储某个具体的类型。
  2. Collection中的常用方法
    • boolean add(Object e) 向集合中添加元素
    • int size() 返回此集合中的元素数。
    • void clear() 清空集合
    • boolean contains(Object o) 判断当前集合是否包含元素o包含返回true
    • boolean remove(Object o) 删除集合中的元素o
    • boolean isEmpty() 判断集合中元素个数是否为0
    • Object[] toArray() 调用这个方法可以把集合转换成数组
package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;

/*
关于java.util.Collection接口中常用的方法
    1.Collection中能存放的元素:
        没有使用“泛型”之前,Collection中可以存储Object的所有子类型。(注意只能存java对象的内存地址)
        使用了“泛型”之后,Collection中只能存储某个具体的类型。
    2.Collection中的常用方法
       boolean add(Object e) 向集合中添加元素
       int size()  返回此集合中的元素数。
       void clear() 清空集合
       boolean contains(Object o) 判断当前集合是否包含元素o包含返回true
       boolean remove(Object o)  删除集合中的元素o
       boolean isEmpty()  判断集合中元素个数是否为0
       Object[] toArray()  调用这个方法可以把集合转换成数组
 */
public class CollectionTest01 {
    public static void main(String[] args) {
        //创建一个集合对象
        //Collection c = new Collection();//接口时抽象的,无法实例化

        Collection c = new ArrayList();//多态

        //测试Collection接口中的常用方法
        c.add(1200);//自动装箱,实际上放进去了一个对象的内存地址。Integer x = new Integer(1200);
        c.add(3.14);//自动装箱
        c.add(new Object());//这是个对象
        c.add(new Student());//对象
        c.add(true);//自动装箱

        //获取集合中的元素个数
        System.out.println("集合中元素个数是:"+c.size());//5

        c.clear();
        System.out.println("集合中元素个数是:"+c.size());//0

        //再向集合中添加元素
        c.add("hello");//"hello"对象的内存地址放到了集合中
        c.add("world");

        //判断集合是否包含hello
        boolean flag = c.contains("hello");
        System.out.println(flag);//true

        boolean flag1 = c.contains("hello world");
        System.out.println(flag1);//false
        System.out.println("集合中元素个数是:"+c.size());//2

        //删除集合中的元素
        c.remove("hello");
        System.out.println("集合中元素个数是:"+c.size());//1

        //判断集合中是否存在元素
        System.out.println(c.isEmpty());//非空返回false
        c.clear();
        System.out.println(c.isEmpty());//清空之之后返回true,表示集合中没有元素了

        c.add("abc");
        c.add("asd");
        c.add(100);
        c.add("hewllo");

        //转换成数组
        Object[] objs = c.toArray();
        for (int i = 0; i< objs.length;i++){
            //遍历数组
            Object o=objs[i];
            System.out.println(o.toString());//不写也自动调用toString方法
        }

    }
}
class Student{

}
输出:
集合中元素个数是:5
集合中元素个数是:0
true
false
集合中元素个数是:2
集合中元素个数是:1
false
true
abc
asd
100
hewllo

3.2 迭代集合

迭代器就是用来把集合中的元素取出来的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CiRid4WK-1616397502363)(F:\学习笔记\学习笔记MD\JAVA学习\JAVApicture\集合\image-20210313102314442.png)]

package com.bjpowernode.javase.collection;

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

/*
集合遍历/迭代专题
 */
public class CollectionTest02 {
    public static void main(String[] args) {
        //注意:以下讲解的遍历方式/迭代方式,是所有Collection通用的一种方式
        //在Map集合中不能用,在所有的Collection以及子类中可以使用
        //创建集合对象
        Collection c = new ArrayList();//后面的集合无所谓,主要是看前面的Collection接口怎么遍历迭代
        //添加元素
        c.add("abc");
        c.add("def");
        c.add(100);
        c.add(new Object());
        //对集合Collection进行迭代
        //第一步:获取集合对象的迭代器对象Iterator
        Iterator it = c.iterator();//Collection接口继承了Iterable接口中的iterator对象
        //第二步:通过以上获取的迭代对象开始迭代/遍历集合
        /*
        iterator对象中有几个常用方法:
        boolean hasNext() 如果仍有元素可以迭代,则返回true
        Object next()返回迭代的下一个元素
         */
//        boolean hasNext = it.hasNext();
//        System.out.println(hasNext);
//        if (hasNext){
//            //不管你当初存进去什么,取出来都是object
//            Object obj = it.next();
//            System.out.println(obj);
//        }
//        hasNext = it.hasNext();
//        System.out.println(hasNext);
//        if (hasNext){
//            Object obj = it.next();
//            System.out.println(obj);
//        }
//        hasNext = it.hasNext();
//        System.out.println(hasNext);
//        if (hasNext){
//            Object obj = it.next();
//            System.out.println(obj);
//        }
//        hasNext = it.hasNext();
//        System.out.println(hasNext);
//        if (hasNext){
//            Object obj = it.next();
//            System.out.println(obj);
//        }
//        hasNext = it.hasNext();
//        System.out.println(hasNext);
//        if (hasNext){
//            Object obj = it.next();
//            System.out.println(obj);
//        }
        //用循环
        while (it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
        }
    }
}
输出:
abc
def
100
java.lang.Object@14ae5a5

测试List集合有序可重复,Set集合无序不可重复

package com.bjpowernode.javase.collection;

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

public class CollectionTest03 {
    public static void main(String[] args) {
       //创建集合对象
        Collection c1 = new ArrayList();
       //添加元素
        c1.add(1);
        c1.add(2);
        c1.add(1);
        c1.add(4);

        //迭代集合
        Iterator it = c1.iterator();
        while (it.hasNext()){
           Object obj = it.next();//取出来的时候是Object类型
            System.out.println(obj);//在打印的时候会转换成字符串,因为println会调用toString方法
            //输出结果有序(放入顺序和取出顺序一致)可重复
        }
        System.out.println("--------------");

        //HashSet集合:无序不可重复
        Collection c2 = new HashSet();
        c2.add(100);
        c2.add(200);
        c2.add(300);
        c2.add(90);
        c2.add(400);
        c2.add(50);
        c2.add(60);
        c2.add(100);//取出来只有一个100
        Iterator it2 = c2.iterator();
        while (it2.hasNext()){
            System.out.println(it2.next());
        }

    }
}
输出:
1
2
1
4   //这里什么顺序存进去,什么顺序拿出来,并且可以重复
--------------
400
50
100
200
90
300
60  //这里顺序被打乱了,并且不能重复

3.3 contains方法分析

他在底层调用了equals方法,而equals方法比较的是内容

package com.bjpowernode.javase.collection;

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

/*
深入研究一下Collection中的contains方法:
    boolean contains(Object o)
        判断集合中是否包含某个对象o
        包含返回true,不包含返回false

 */
public class CollectionTest04 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();
        String s1 = new String("abc");
        c.add(s1);

        String s2 = new String("def");
        c.add(s2);
        //集合中元素个数
        System.out.println("元素个数是:"+c.size());

        //新建对象String
        String x = new String("abc");
        //判断c集合中是否包含abc
        System.out.println(c.contains(x));//true,这里判断的是内容,底层调用了equals方法
        //


    }
}
true

java集合_第7张图片

package com.bjpowernode.javase.collection;

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

public class CollectionTest05 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();
        //创建用户对象
        User u1= new User("jack");
        User u2= new User("jack");
        //加入集合
        c.add(u1);
        //判断集合中是否包含u2
        System.out.println(c.contains(u2));
        //这里如果User类没有重写equals方法,会调用公共父类Object,而Object里的equals方法比较
        //的是两个对象的地址,所以没有重写之前是false
        Integer x = new Integer(1000);
        c.add(x);
        
        Integer y = new Integer(1000);
        System.out.println(c.contains(y));//重写之后true
        
    }

}
class User{
    private String name;
    public User(){};
    public User(String name){
        this.name = name;
    }

    //重写equals方法


    public boolean equals(Object obj) {
        if (obj == null ||!(obj instanceof User)) return false;//传进来的对象是空或者不是一个User子类的时候返回false
        if (obj == this)return true;//如果对象和这个比较类的内存地址一样返回true
        User u =(User)obj;
        return u.name.equals(this.name);//如果名字一样表示同一个人
    }
}
//结论:存放在集合中的类型,一定要重写equals方法

3.4 remove方法分析

package com.bjpowernode.javase.collection;

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

public class CollectionTest05 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();
        //创建用户对象
        User u1= new User("jack");
        User u2= new User("jack");
        //加入集合
        c.add(u1);
        //判断集合中是否包含u2
        System.out.println(c.contains(u2));
        //这里如果User类没有重写equals方法,会调用公共父类Object,而Object里的equals方法比较
        //的是两个对象的地址,所以没有重写之前是false
        c.remove(u2);
        System.out.println(c.size());//你在下面重写了equals所以因为u1和u2的内容一样,
        // 删掉u2就等于删掉u1。如果不重写equals他比较的是内存地址,那就删不掉了。

        Integer x = new Integer(1000);
        c.add(x);

        Integer y = new Integer(1000);
        System.out.println(c.contains(y));//重写之后true



        //创建集合对象
        Collection cc = new ArrayList();
        String s1 = new String("hello");
        //加进去
        cc.add(s1);
        //创建一个新的字符串对象
        String s2 = new String("hello");
        //删除s2
        cc.remove(s2);
        //集合中的元素
        System.out.println(cc.size());//结果是0,因为remove也是调用了equals,

    }

}
class User{
    private String name;
    public User(){};
    public User(String name){
        this.name = name;
    }

    //重写equals方法


    public boolean equals(Object obj) {
        if (obj == null ||!(obj instanceof User)) return false;//传进来的对象是空或者不是一个User子类的时候返回false
        if (obj == this)return true;//如果对象和这个比较类的内存地址一样返回true
        User u =(User)obj;
        return u.name.equals(this.name);//如果名字一样表示同一个人
    }
}
//结论:存放在集合中的类型,一定要重写equals方法
  • 集合结构发生改变时,迭代器必须重新获取。
    • 在迭代集合过程中,不能调用集合对象的remove方法删除元素
    • 用迭代器的remove方法删除
  • 原因(大概理解):
    • Iterator it2 = c2.iterator();获取迭代器对象之后,迭代器用来遍历集合,此时相当于对当前集合状态拍了一个快照,迭代器迭代的时候会参照这个快照去迭代,当用集合直接删除元素的时候,相当于没有通知迭代器,导致集合中删除了,快照中没删除,报错。
    • 当用迭代器去删除,就相当于把快照里的集合删了(自动更新迭代器),同时把集合里的元素也删了,就不会报错。
package com.bjpowernode.javase.collection;

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

/*
关于集合元素的remove
    重点:当集合结构发生改变时,迭代器必须重新获取,如果还是用以前老的迭代器,会出现异常:java.util.ConcurrentModificationException

    重点:在迭代集合过程中,不能调用集合对象的remove方法删除元素,会出现java.util.ConcurrentModificationException
 */
public class CollectionTest06 {
    public static void main(String[] args) {
        //创建集合
       /* Collection c = new ArrayList();
        //注意:如果在这个地方即没有添加元素之前获取迭代器,他指向的是集合中没有元素状态下的迭代器
        //一定要注意:集合结构只要发生改变,迭代器必须重新获取。
        //当集合结构发生改变,迭代器没有重新获取时,调用next()方法报错:java.util.ConcurrentModificationException
        //Iterator it = c.iterator();

        //添加元素
        c.add(1);//Integer类型
        c.add(2);
        c.add(3);
        c.add(4);
        //获取迭代器
        Iterator it = c.iterator();
        while (it.hasNext()){
            Object obj = it.next();//编写代码时,next()方法返回值必须是Object
            System.out.println(obj);//obj就代表集合当中的元素
        }*/

        Collection c2 = new ArrayList();
        c2.add("abc");
        c2.add("def");
        c2.add("xyz");

        Iterator it2 = c2.iterator();
        while (it2.hasNext()){
            Object o = it2.next();
            //删除元素
            //删除元素之后,集合的结构发生了变换,应该重新获取迭代器,但是循环下一次的时候没有重新获取迭代器
            //会出现java.util.ConcurrentModificationException

            //c2.remove(o);//直接通过集合去删除元素,没有通知迭代器(导致迭代器的快照和原集合状态不同)

            //使用迭代器来删除
            it2.remove();//删除的一定是迭代器指向的当前元素
            System.out.println(c2.size());
        }
    }
}
2
1
0

4. List接口的特有方法

package com.bjpowernode.javase.collection;

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

/*
List接口中的常用方法
    1.List集合存储元素特点:有序可重复
        有序:List集合中的元素有下标。从0开始以1递增。
        可重复:存储一个1,还可以再存储1。
    2.List方法既然是Collection接口的子接口,那么肯定List接口有自己"特色"的方法:
        以下只列出List接口特有的常用方法:
            void add(int index, Object element)  在指定下标位置上添加元素,第一个元素是下标,添加之后后面的以此移位
            Object get(int index)  返回指定下标的元素
            int indexOf(Object o)  返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
            int lastIndexOf(Object o)  返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
            Object remove(int index)  删除该列表中指定位置的元素
            Object set(int index, Object element)  修改指定下标位置的元素
            
            以后开发可以翻阅文档

 */
public class ListTest01 {
    public static void main(String[] args) {
        //创建List类型的集合
        List myList = new ArrayList();

        //添加元素
        myList.add("A");
        myList.add("B");
        myList.add("C");
        myList.add("C");
        myList.add("D");//默认往集合末尾添加指定元素
        myList.add(1,"King");//在指定下标位置上添加元素,效率比较低,不常用

        //迭代
        Iterator iterator = myList.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();

            System.out.println(obj);
        }
        System.out.println("--------------------------");

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

        //因为有下标,所以List方法有自己特殊的遍历方式---通过下标遍历【set没有】

        for (int i = 0; i < myList.size(); i++) {
            Object o = myList.get(i);
            System.out.println(o);
        }
        System.out.println("-----------------");

        //获取指定对象第一次出现处的索引。
        System.out.println(myList.indexOf("King"));// 1

        //获取指定对象最后一次出现处的索引
        System.out.println(myList.lastIndexOf("C"));//4

        //删除指定下标位置的元素
        myList.remove(0);
        System.out.println(myList.size());//5
        System.out.println("------------------");

        //修改指定下标位置的元素
        myList.set(2,"Soft");

        //遍历集合

        for (int i = 0; i < myList.size(); i++) {
            Object o = myList.get(i);
            System.out.println(o);
        }


    }
}
输出:
A
King
B
C
C
D
--------------------------
A
A
King
B
C
C
D
-----------------
1
4
5
------------------
King
B
Soft
C
D

4.1 ArrayList集合

ArrayList集合:

  • ArrayList集合初始化容量是10
  • 底层是Object类型的数组Object[]
  • 构造方法:
    • new ArrayList()
    • new ArrayList(20)
    • ArrayList(Collection c)
  • ArrayList集合扩容:
    • 扩容后的容量是原来容量的1.5倍。
    • ArrayList集合底层是数组,要尽可能少的扩容,因为数组扩容效率比较低,建议在使用ArrayList集合的时候预计估计集合个数,给定初始化容量。
  • ArrayList是非线程安全的

数组的优缺点:

  • 数组的优点:检索效率比较高。(每个元素占用空间大小相同,内存地址是连续的,知道首元素地址,然后知道下标,通过数学表达式计算内存地址,所以检索效率最高)
  • 数组缺点:随机增删元素效率比较低。但是向数组末尾添加元素效率还是比较难高的数组无法存储大数据量,因为很难找到一块大的连续的内存空间

补充:>>右移、<<左移运算符,右移一位相当于/2,左移一位相当于*2

package com.bjpowernode.javase.collection;

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

/*
ArrayList集合:
    1.默认初始化容量是10
    2.集合底层是一个Object[]数组
    3.构造方法:
        new ArrayList()
        new ArrayList(20)

    4.ArrayList集合扩容:
        扩容后的容量是原来容量的1.5倍
        ArrayList集合底层是数组,要尽可能少的扩容,因为数组扩容效率比较低,建议在使用ArrayList集合的时候
        预计估计集合个数,给定初始化容量。
    5.数组优缺点:
        数组的优点:检索效率比较高。(每个元素占用空间大小相同,内存地址是连续的,知道首元素地址,然后知道
        下标,通过数学表达式计算内存地址,所以检索效率最高)
        数组缺点:随机增删元素效率比较低。但是向数组末尾添加元素效率还是比较难高的
                数组无法存储大数据量,因为很难找到一块大的连续的内存空间

    6.面试官问:这么多集合用那个集合比较多:
        ArrayList集合,因为往数组末尾添加元素,效率不受影响,另外我们检索\查找某个元素比较多。
 */
public class ArrayListTest01 {
    public static void main(String[] args) {
        //默认初始化容量是10
        //数组的长度是10
        List List1 = new ArrayList();
        //集合的size方法是获取当前结合中元素的个数
        System.out.println(List1.size());//0

        //指定初始化容量
        //数组长度是20
        List List2 = new ArrayList(20);
        System.out.println(List2.size());//0


    }
}

  • 三种构造方法
package com.bjpowernode.javase.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/*
集合ArrayList的构造方法
 */
public class ArrayListTest02 {
    public static void main(String[] args) {
        //初始化容量10
        ArrayList myList1 = new ArrayList();
        //指定初始化容量100
        ArrayList myList2 = new ArrayList(100);

        //创建一个HashSet集合
        Collection c = new HashSet();

        //添加元素到Set集合
        c.add(100);
        c.add(200);
        c.add(300);

        //通过这个构造方法就可以将HashSet集合转换成List集合。
        List myList3 = new ArrayList(c);
        for (int i = 0; i < myList3.size(); i++) {
            System.out.println(myList3.get(i));
        }
    }
}
100
200
300

4.2 LinkedList

4.2.1 单向链表数据结构

java集合_第8张图片

  • 链表优点:

    • 随机增删元素效率比较高。(因为链表上的元素在空间内存上的地址不连续,增删元素不涉及大量的元素位移问题),如果开发中遇到随机增删集合中元素业务比较多时,建议使用LinkedList
  • 链表缺点:

    • 查询效率比较低,每一次查找某个元素的时候都需要从头节点开始

链表中的元素,在空间存储上,内存地址不连续。

我们一般添加元素都是往末尾添加,所以ArrayList用的比较多

  • 节点
package com.bjpowernode.javase.danLink;
/*
单链表中的节点
节点是单向链表中的基本单元。
每个节点Node都有两个属性:
    一个属性是存储数据
    另一个属性是下一个节点的内存地址。
 */
public class Node {
    //存储数据
    Object data;
    //下一个节点的内存地址
    Node next;

    public Node(){

    }

    public Node(Object data,Node next){
        this.data = data;
        this.next = next;
    }
}
  • 链表
package com.bjpowernode.javase.danLink;

public class Link {
    //头节点
    Node header = null;

    int size = 0;
    public int size(){
        return size;
    }

    //向链表中添加元素(向末尾添加)
    public void add(Object data){
        //创建一个新的节点对象
        //让之前单链表的末尾节点next指向新的节点对象。
        //有可能这个元素是第一个,也可能不是第一个。
        if (header == null){
            //说明还没有节点,就new一个新的节点对象作为头节点对象。
            //这时候的头节点既是头节点,又是末尾节点。
            header = new Node(data,null);
        }else {
            //说明头不是空,头节点已经有了
            //找出当前末尾节点,让当前末尾节点的next是新的节点
            Node currentLastNode = finaLast(header);
            currentLastNode.next = new Node(data,null);
        }
        size++;

    }

    /**
     * 专门查找末尾节点的方法
     * @param
     * @return
     */
    private Node finaLast(Node node) {
        if (node.next == null){//如果一个节点的next是null说明这个几点是末尾节点
        return node;
        }
        return finaLast(node.next);//用递归去找
    }

    //删除链表中某个元素的方法
    public void remove(Object obj){

    }
}
  • Test
package com.bjpowernode.javase.danLink;

public class Test {
    public static void main(String[] args) {
        //创建了一个集合
        Link link = new Link();
        //往集合中添加元素
        link.add(100);
        link.add(200);
        link.add(300);
        link.add(400);
        //获取元素个数
        System.out.println(link.size);
    }
}
输出:4

4.2.2 双向链表数据结构

java集合_第9张图片

package com.bjpowernode.javase.collection;

import java.util.LinkedList;
/*
LinkedList没有初始化容量,这个链表中没有任何元素,first和last引用都是null
不管是LinkedList还是ArrayList,以后写代码是面向接口编程
LinkedList list = new ArrayList();代表底层是数组
LinkedList list = new LinkedList();代表底层是双向链表,后面都是用list这个引用来调方法编程。
 */
public class LinkedListTest01 {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");

        for (int i = 0; i < list.size(); i++) {
            Object obj = list.get(i);
            System.out.println(obj);
        }
    }
}
输出:
a
b
c    

4.3 Vector

package com.bjpowernode.javase.collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;

/*
Vector:
    1.底层是一个数组。
    2.初始化容量:10
    3.Vector:扩容之后是原来容量的2倍
    4.ArrayList集合扩容特点:是原来容量的1.5倍
    5.Vector中所有的方法都是线程同步的,都是synchronized关键字修饰的,是线程安全的,效率较低。
    6.如何把一个线程不安全的ArrayList集合转化成线程安全的?
        使用集合工具类:
            java.util.Collections
            
            java.util.Collection是集合接口
    
 */
public class VectorTest {
    public static void main(String[] args) {
        List vector = new Vector();
        vector.add(1);
        vector.add(2);
        vector.add(3);
        vector.add(4);
        vector.add(5);
        vector.add(6);
        vector.add(7);
        vector.add(8);
        vector.add(9);
        vector.add(10);
        vector.add(11);

        for (int i = 0; i < vector.size(); i++) {
            System.out.println(vector.get(i));
        }
        
        List mylist = new ArrayList();//非线程安全的
        
        //变成线程安全的
        Collections.synchronizedList(mylist);
        mylist.add("111");
        mylist.add("222");
        mylist.add("333");
    }
}

5. 泛型

5.1 泛型存在的意义

package com.bjpowernode.javase.collection;

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

/*
1.JDK5.0之后推出的新特性:泛型
2.泛型这种机制,只在程序编译阶段起作用,只是给编译器参考的。(运行阶段意义不大)
3.使用泛型的好处:
    1.集合中存储的元素类型统一了
    2.从集合中取出的元素类型是泛型指定的类型,不需要进行大量的"向下转型"!
4.泛型的缺点:
    1.导致集合中存储的元素缺乏多样性
5.实际开发中,集合中元素大多是统一的
 */
public class GenericTese01 {
    public static void main(String[] args) {
      /*  //不使用泛型,分析程序存在的缺点
        List mylist = new ArrayList();

        //准备对象
        Cat c = new Cat();
        Bird b = new Bird();

        //将对象加到集合里
        mylist.add(c);
        mylist.add(b);

        //遍历集合,取出每个对象让他move
        Iterator it = mylist.iterator();
        while (it.hasNext()){
            Object obj = it.next();
            //obj中没有move方法,无法调用,只能向下转型。
            if (obj instanceof Animal){
                Animal a = (Animal)obj;
                a.move();
            }
        }
        */

        //使用JDK5之后的泛型机制
        //使用泛型List之后,表示List集合只允许存储Animal类型的数据。
        //用泛型来指定集合中存储的数据类型,集合元素的数据类型更加统一
        List<Animal> mylist = new ArrayList<Animal>();
        //mylist.add("a");报错

        Cat cat = new Cat();
        Bird bird = new Bird();
        mylist.add(cat);
        mylist.add(bird);

        //获取迭代器
        //加入泛型之后表示迭代器迭代得是Animal类型
        Iterator<Animal> it = mylist.iterator();
        while (it.hasNext()){
            //使用泛型之后,每次迭代返回的数据都是Animal类型,这里不需要强制类型转换
            Animal a = it.next();//直接可以拿到Animal
            a.move();

            //调用子类特有方法还是需要转换
            if (a instanceof Cat){
                Cat c = (Cat)a;//你调用子类特有方法还是得向下转型
                c.catchMouse();
            }
            if (a instanceof Bird){
                Bird b = (Bird)a;//你调用子类特有方法还是得向下转型
                b.fly();
            }

        }

    }
}
class Animal{
    public void move(){
        System.out.println("动物在移动");
    }

}

class Cat extends Animal{
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }

}

class Bird extends Animal{
    public void fly(){
        System.out.println("鸟儿在飞翔");
    }
}

输出:
动物在移动
猫抓老鼠
动物在移动
鸟儿在飞翔

5.2 类型自动推断

package com.bjpowernode.javase.collection;

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

/*
JDK8之后引入了自动类型推断机制。又称为钻石表达式
 */
public class GenericTest02 {
    public static void main(String[] args) {
        //ArrayList<这里的类型会自动推断>,前提是JDK8之后才允许。
        List<Animal> myList = new ArrayList<>();

        myList.add(new Animal());
        myList.add(new Cat());
        myList.add(new Bird());

        //遍历

        Iterator<Animal> it = myList.iterator();
        while (it.hasNext()){
            Animal a = it.next();
            a.move();
        }

        List<String> stringList= new ArrayList<>();

        stringList.add("abc");
        stringList.add("http//baidu.com");

        //遍历
        Iterator<String> iterator = stringList.iterator();

        while (iterator.hasNext()){
            String next = iterator.next();//这个迭代器返回的就是String
            System.out.println(next);
        }
    }
}
输出:
动物在移动
动物在移动
动物在移动
abc
http//baidu.com

5.3 自定义泛型

package com.bjpowernode.javase.collection;
/*
自定义泛型
    <>尖括号中的是一个标识符,随便写
    java源代码中经常出现的是,
    E是Element单词首字母
    T是Type单词首字母
    
 */
public class GenericTest03<标识符随便写> {
    public void doSome(标识符随便写 o){
        System.out.println(o);
    }
    
    public static void main(String[]args){
        //new对象的时候指定了是String
        GenericTest03<String> gt = new GenericTest03<>();//真正起作用的是在new对象的时候指定的那个类型
        gt.doSome("这里只能是String");
     
        
        GenericTest03<Integer> gt2 = new GenericTest03<>();
        gt2.doSome(100);//这里只能是Integer类型,自动装箱
    }
    
}
输出:
这里只能是String
100

6. 增强for循环

语法:

for(元素类型 变量名:数组或者集合){
          代码;
        }
package com.bjpowernode.javase.collection;
/*
JDK5.0之后推出了一个新特性:叫做增强for循环,或者叫foreach
 */
public class ForEachTest01 {
    public static void main(String[] args) {
        //int类型数组
        int[] arr = {45,25,36,88,95};
        //遍历数组
        for (int i = 0; i < arr.length; i++) {//普通for循环
            System.out.println(arr[i]);
        }
        //增强for循环(foreach)
        /*for(元素类型 变量名:数组或者集合){
          System.out.println(变量名);
        }*/
        
        //foreach有个缺点是没有下标,在需要使用下标的循环中不建议使用
        System.out.println("====================");
        for(int data:arr){
            //data就是数组中的元素
            System.out.println(data);
        }
    }
}
输出:
45
25
36
88
95
====================
45
25
36
88
95
  • 在集合中使用增强for
package com.bjpowernode.javase.collection;

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

/*
集合使用foreach
 */
public class ForEachTest02 {
    public static void main(String[] args) {
        //创建List集合
        List<String > stringList = new ArrayList<>();
        //添加元素
        stringList.add("hello");
        stringList.add("world");
        stringList.add("kitt");
        stringList.add("thanks");

        //遍历,使用迭代器方式

        Iterator<String> iterator = stringList.iterator();
        while (iterator.hasNext()){
            String s = iterator.next();
            System.out.println(s);
        }
        System.out.println("=================");
        //使用下标,只针对有下标的集合
        for (int i = 0; i < stringList.size(); i++) {
            System.out.println(stringList.get(i));
        }
        System.out.println("====================");

        //使用增强for
        for (String s:stringList){//s代表集合中的元素
            System.out.println(s);
        }

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

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        for (int i : list) {//i代表集合中的元素
            System.out.println(i);
        }

    }
}
输出:
hello
world
kitt
thanks
=================
hello
world
kitt
thanks
====================
hello
world
kitt
thanks
============
1
2
3

7. HashSet集合特点演示

package com.bjpowernode.javase.collection;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/*
HashSet集合特点:无序不可重复
 */
public class HashSetTest01 {
    public static void main(String[] args) {
        //演示以下HashSet的特点
        Set<String> strs = new HashSet<>();

        //添加元素
        strs.add("hello");
        strs.add("hello1");
        strs.add("hello2");
        strs.add("hello3");
        strs.add("hello1");
        //遍历
        for(String s : strs){
            System.out.println(s);
        }
        /*
        hello1
        hello2
        hello  
        hello3  
        1.存储的顺序和取出来的顺序不同
        2.不可重复
        3.放到HashSet集合中的元素实际是放到HashMap的Key部分了
         */
    }
}

8. TreeSet集合特点演示

package com.bjpowernode.javase.collection;

import java.util.Set;
import java.util.TreeSet;

/*
TreeSet集合特点:
    1.无序不可重复,但是存储的元素可以自动按照大小顺序排序
    称为:可排序集合
    
    2.这里的无序是存进去的顺序和取出来的顺序不同,并且没有下标
 */
public class TreeSetTest {
    public static void main(String[] args) {
        //创建集合对象
        Set<String> strs = new TreeSet<>();
        //添加元素
        strs.add("A");
        strs.add("B");
        strs.add("C");
        strs.add("D");
        strs.add("D");
        strs.add("M");
        strs.add("Z");
        strs.add("K");

        //遍历
        for (String s : strs) {
            System.out.println(s);
        }
        /*
        A
        B
        C
        D
        K
        M
        Z
        从小到大自动排序
         */

    }
}
输出:
A
B
C
D
K
M
Z

9. Map集合常用方法

Interface Map 支持泛型

package com.bjpowernode.javase.collection;
/*
java.util.Map接口中常用的方法
    1.Map和Collection没有继承关系
    2.Map集合以Key和Value的方式存储数据:键值对
        Key和Value都是引用数据类型。
        key和Value都是存储对象的内存地址。
        Key起到主导地位,Value是Key的一个附属品

    3.Map接口中的常用方法:
        V put(K key, V value) 向Map集合中添加键值对
        V get(Object key) 通过Key获取Value
        void clear() 清空Map集合
        boolean containsKey(Object key) 判断Map集合中是否包含某个Key
        boolean containsValue(Object value) 判断Map集合中是否包含某个Key

        boolean isEmpty() Map集合中的元素个数是否为0
        Set keySet() 获取Map集合中所有的Key 他返回是个Set集合,印证了HashSet加数据是放到了Map集合的Key部分

        V remove(Object key) 通过Key删除键值对
        int size() 返回Map集合中键值对的个数
        Collection values()  获取Map集合中所有的Value,返回Collection
        Set> entrySet()
            将Map集合转换成Set集合
            假设现在有一个Map集合,如下图
                map1集合对象
                ---------------------
                Key             Value
                1               zhangsan
                2               lisi
                3               wangwu
                4               zhaoliu

                Set set = map1.entrySet();
                Set集合对象
                1=zhangsan
                2=lisi
                3=wangwu
                4=zhaoliu
            【注意】:Map集合通过entrySet()方法转换成的Set集合,Set集合中的元素类型是Map.Entry
            Map.Entry和String一样是一种类型的名字,只不过Map.Entry是是Map中的静态内部类

 */

  • 关于Set> entrySet()方法的理解 Set集合里面对象的类型是Map.Entry类型
package com.bjpowernode.javase.collection;

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

public class MyClass {

    //声明一个静态内部类
    private static class InnerClass{
        //静态方法
        public static void m1(){
            System.out.println("静态内部类的m1方法执行");

        }
        //实例方法(非静态方法)
        public void m2(){
            System.out.println("静态内部类的实例方法");
        }


    }
    public static void main(String[]args){
        //类名MyClass.InnerClass
        MyClass.InnerClass.m1();
        //创建静态内部类对象
        MyClass.InnerClass mi = new MyClass.InnerClass();
        mi.m2();

        //给一个Set集合
        //该Set集合中存储的对象是:MyClass.InnerClass类型
        Set<MyClass.InnerClass> set = new HashSet<>();

    }

}

  • 常用方法测试
package com.bjpowernode.javase.collection;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class MapTest01 {
    public static void main(String[] args) {
        //创建Map集合对象
        Map<Integer,String> map = new HashMap<>();
        //向Map集合中添加键值对
        map.put(1,"zhangsan");//自动装箱
        map.put(2,"lisi");
        map.put(3,"wangwu");
        map.put(4,"zhaoliu");
        //通过key获取Value
        String value = map.get(2);
        System.out.println(value);//lisi

        //获取键值对的数量
        System.out.println(map.size());//4

        //通过key删除value
        map.remove(2);
        System.out.println(map.size());//3

        //判断是否包含某个key
        //contains方法底层调用的都是equals,自定义的数据类型需要重写equals方法
        System.out.println(map.containsKey(4));//true
        //判断是否包含某个value
        System.out.println(map.containsValue("lisi"));//false

        //获取所有的value
        Collection<String> values = map.values();
        for (String s : values) {
            System.out.println(s);
        }/* zhangsan
            wangwu
            zhaoliu*/

        //清空键值对
        map.clear();
        System.out.println(map.size());//0

        //判断是否为空
        System.out.println(map.isEmpty());//true

    }
}

  • 遍历Map集合(方式1)
package com.bjpowernode.javase.collection;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/*
Map集合的遍历
 */
public class MapTest02 {
    public static void main(String[] args) {
        //第一种方式:获取所有的key,通过遍历key来遍历value
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"张三");
        map.put(2,"李四");
        map.put(3,"王五");
        map.put(4,"赵六");
        //遍历Map集合
        //获取所有的Key,所有的Key是一个set集合
        Set<Integer> keys = map.keySet();
        //迭代器可以
        Iterator<Integer> iterator = keys.iterator();
        while (iterator.hasNext()){
            //取出其中一个key
            Integer key = iterator.next();
            //通过key获取value
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }

        for (Integer k :keys){
            System.out.println(k + "=" + map.get(k));
        }
    }
}
输出:
1=张三
2=李四
3=王五
4=赵六
=================
1=张三
2=李四
3=王五
4=赵六

  • 第二种方式遍历Map集合

java集合_第10张图片

package com.bjpowernode.javase.collection;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/*
Map集合的遍历
 */
public class MapTest02 {
    public static void main(String[] args) {
        //第一种方式:获取所有的key,通过遍历key来遍历value
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"张三");
        map.put(2,"李四");
        map.put(3,"王五");
        map.put(4,"赵六");
        
        //第二种方式:Set> entrySet()
        //把Map集合直接全部转换成Set集合
        //Set集合中的元素类型是:Map.Entry
        Set<Map.Entry<Integer,String>> set = map.entrySet();
        //遍历Set集合,每一次取出一个Node

        //迭代器
        /*
        Iterator> it = set.iterator();
        while (it.hasNext()){
            Map.Entry node = it.next();
            Integer key = node.getKey();
            String value = node.getValue();
            System.out.println(key + "=" +value);
        }*/
        //foreach 
        //效率比较高,因为获取key和value都是直接从node对象中获取属性值
        for (Map.Entry<Integer,String >node:set){
            System.out.println(node.getKey() + "=" + node.getValue());
            //这个getKey()和getValue()是Map.Entry这个类的方法
        }

    }
}
输出:
1=张三
2=李四
3=王五
4=赵六

你可能感兴趣的:(笔记,java)