JAVA--集合

一、集合概念

集合–>存储容器

引入

举个例子,创建一个学生表,底层用数组来实现,当需要删除某一个学生数据时,仅仅是通过将所要删除的数组元素赋值为null,实际上数组长度没变,当需要添加新的数据时,又要考虑数组容量问题,毕竟数组一经声明,容量就是固定的,不太灵活。

然而在实际中,我们经常需要保存一些变长的数据集合,这时就需要能够动态增长长度的容器来存储数据。

为了满足程序运行中各种变化的数据存储需求,java语言中,封装了许多的了类,
来帮助我们完成不同数据的存储,这些类就被称为集合类.

核心思想就是我们要学习一些类,这些类对数组等数据结构进行了封装,可以让我们更加方便的使用.

二、集合 API

(一)集合体系概述

Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中

4个接口 7个实现类

单列集合
Collection
List 可以存储重复元素

​ ArrayList 数据列表

​ LinkedList 链表列表

​ Vector 线程安全的数组列表

​ Set
​ HashSet 哈希集合
​ TreeSet 树形集合

双列集合

​ Map

​ 键 : 值
​ HashMap
​ TreeMap

java中提供不同结构的容器类,来存储不同的数据

(二)Collection接口

Collection 接口-定义了存取一组对象的方法,其子接口Set和List分别定义

了存储方式。

List:数据元素可以重复,有顺序(添加顺序),还可以通过索引操作

Set:不能重复,添加时会自动判断,没有顺序(有的有序,有的无序)

三、List 接口及实现类

List继承了Collection接口,有三个实现的类

​ ArrayList 数据列表

​ LinkedList 链表列表

​ Vector 数据列表(线程安全)

List中方法名相同,但具体底层实现完全不同

(一)ArrayList: 数组列表

由于数组中的每个空间都是连续的,所以查询非常方便,可以直接通过下标获取指定位置的元素,但是从中间要删除元素,就比较麻烦,删除后其他元素要进行位移.
查询快,中间删除添加慢
ArrayList可以动态的增加数组长度

Ep1:

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

public class ArrayListDemo1 {
    /*
    ArrayList
    底层有一个transient Object[] elementData; 数组
    默认是向集合的末尾添加元素,首次底层会初始化一个长度为10的数组,当元素添加满了的时候,会发生扩容操作,扩容为原来的1.5倍
    ArrayList  默认可以存储任意类型的数据
    ArrayList<E> 建议使用泛型的语法,为集合中存储的数据设定数据类型,
    java中的集合,建议只存储一类类型
    */
    
    public static void main(String[] args) {
        ArrayList<String> alist =   new ArrayList<String>();
        alist.add("a");//向末尾添加
        alist.add("b");
        alist.add("c");
        alist.add("d");
        alist.add("e");
        alist.add("f");
        alist.add("g");
        alist.add("h");
        alist.add("i");
        alist.add("j");
        alist.add("k");
        alist.add("l");
        alist.add(0, "A");//向指定的位置添加
        alist.remove(1);//删除指定位置的元素
        alist.remove("h");//删除指定内容的元素
        System.out.println(alist.size());//获取集合中实际有多少个元素
        System.out.println(alist.get(4));//获取指定位置上的元素
        System.out.println(alist);
        alist.clear();//将数组列表清空
        System.out.println(alist);
    }
}
/*
11
e
[A, b, c, d, e, f, g, i, j, k, l]
[]

*/

Ep2:

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

public class ArrayListDemo2 {
    public static void main(String[] args) {
        ArrayList<String> alist =   new ArrayList<String>();//默认容量是10
        alist.add("a");
        alist.add("b");
        alist.add("c");
        alist.add("d");
        alist.add("c");
        System.out.println(alist.contains("d"));//判断是否包含指定的元素
        System.out.println(alist.isEmpty());//判断集合是否为空
        //alist.ensureCapacity(20); 扩容为指定容量
        System.out.println(alist.indexOf("c"));//获取指定元素首次出现的位置 从前向后找
        System.out.println(alist.lastIndexOf("c"));//获取指定元素首次出现的位置 从后向前找
        alist.set(0, "A");//将指定位置上的元素替换为给定元素
        Object[] objs =  alist.toArray();//将集合转为Object类型
        System.out.println(objs.length);
        String [] arrays =   alist.toArray(new String[alist.size()]);//将集合转为一个String类型的数组
        System.out.println(Arrays.toString(arrays));
        System.out.println(alist);
    }
}
/*
true
false
2
4
5
[A, b, c, d, c]
[A, b, c, d, c]
*/

(二)LikedList: 链表列表

每一个数据存储在一个Node类中 Node节点
Node
prev(前驱)
data(数据)
next(后继)

链表结构,对外只提供头,尾节点,每次查询元素时,非常慢,必须从头或者从尾开始

如果从中间删除某个元素时非常快,只需要改变next节点的内存地址即可(即将前一个next节点指向后一个prev节点),元素不需要移动位置

查询慢,但是中间添加删除快

Ep:

import java.util.LinkedList;

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<String> llist = new LinkedList<>();
        llist.add("a");
        llist.add("b");
        llist.add("c");
        llist.add("d");
        llist.add("e");
        llist.add("f");
        llist.add(1, "AA");
        System.out.println(llist);
        System.out.println(llist.get(3));//返回指定索引位上的元素
        llist.remove(4);//删除指定索引位上的元素
        System.out.println(llist);
        llist.remove("c");//删除指定元素
        System.out.println(llist);
        System.out.println(llist.size());
        //LinkedList可以用来实现队列和栈结构容器
        llist.addFirst("A");//给首位添加元素
        System.out.println(llist);
        llist.addLast("N");
        System.out.println(llist);
        System.out.println(llist.getFirst());//返回首位元素
        System.out.println(llist.getLast());
        System.out.println(llist);
        System.out.println(llist.removeFirst());//返回并删除首位元素
        System.out.println(llist.removeLast());
        System.out.println(llist);
    }
}

/*
[a, AA, b, c, d, e, f]
c
[a, AA, b, c, e, f]
[a, AA, b, e, f]
5
[A, a, AA, b, e, f]
[A, a, AA, b, e, f, N]
A
N
[A, a, AA, b, e, f, N]
A
N
[a, AA, b, e, f]
*/

(三)Vector

与ArrayList基本类似

List Vector 数组列表 里面的方法,都添加 synchronized关键字,是线程安全的

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

四、List接口集合迭代

(一)for循环遍历

import java.util.ArrayList;

public class ListFor {

    public static void main(String[] args) {
        ArrayList<String> alist = new ArrayList();
        alist.add("a");//向末尾添加
        alist.add("b");
        alist.add("c");
        alist.add("d");
        alist.add("e");
		//for循环进行遍历
		    for(int i=0;i<alist.size();i++){
		        String item = alist.get(i);
		    	System.out.println(item);
		}
    }

}
/*
a
b
c
d
e
*/
import java.util.ArrayList;

public class ListFor {

    public static void main(String[] args) {
        ArrayList<String> alist = new ArrayList();
        alist.add("a");//向末尾添加
        alist.add("b");
        alist.add("c");
        alist.add("d");
        alist.add("e");
        /*
		   for循环进行遍历
		       在遍历元素时,是可以删除元素的,删除元素时,需要注意元素的移动,以及索引的变化
		 */
		   for(int i=0;i<alist.size();i++){
		    	String item = alist.get(i);
		    	if(item.equals("c")){
		    		alist.remove(item);
		    		i--;
		    	}
		    } 
		   System.out.println(alist);
    }
}
/*
[a, b, d, e]
*/

(二)增强for循环的遍历

import java.util.ArrayList;

public class ListFor {

    public static void main(String[] args) {
        ArrayList<String> alist = new ArrayList();
        alist.add("a");//向末尾添加
        alist.add("b");
        alist.add("c");
        alist.add("d");
        alist.add("e");
        //增强for循环
        for(String item :  alist){
            System.out.println(item);
        }
    }
}
/*
a
b
c
d
e
*/
import java.util.ArrayList;

public class ListFor {

    public static void main(String[] args) {
        ArrayList<String> alist = new ArrayList();
        alist.add("a");//向末尾添加
        alist.add("b");
        alist.add("c");
        alist.add("d");
        alist.add("e");	   
		 /*
		        增强for循环
		        在遍历元素时,不允许从集合中删除元素,如果删除元素报异常ConcurrentModificationException
		  */
	       for(String item :  alist){
	    	   if(item.equals("c")){
	    		   alist.remove(item);
	    	   }
	       }
	       System.out.println(alist);
		
    }

}
/*
[a, b, d, e]
*/

(三)迭代器遍历(Iterator)

java中提供了对集合进行遍历的迭代器
里面维护了一个指针(计数器),当删除元素时,计数器会自动回退

import java.util.ArrayList;
import java.util.ListIterator;

public class listiteratorDemo {
    public static void main(String[] args) {

        ArrayList<String> alist =   new ArrayList();
        alist.add("a");//向末尾添加
        alist.add("b");
        alist.add("c");
        alist.add("c");
        alist.add("d");
        alist.add("e");

	      /*
	         java中提供了对集合进行遍历的迭代器
	                       里面维护了一个指针(计数器),当删除元素时,计数器会自动回退
	       */
        //获取集合的迭代器
	        /*ListIterator<String> lit =   alist.listIterator();
	                    while(lit.hasNext()){
	                    	String item = lit.next();
	                    	System.out.println(item);
	                    }*/

        // 从后向前进行遍历                                给定开始的位置
        ListIterator<String> list = alist.listIterator(alist.size()); //0-5 6
        //从后向前进行遍历
        while(list.hasPrevious()){
            String item = list.previous();//取出前一个
            System.out.println(item);
        }
    }
}

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

public class iteratorDemo {
    public static void main(String[] args) {
        ArrayList<String> alist =   new ArrayList();
        alist.add("a");//向末尾添加
        alist.add("b");
        alist.add("c");
        alist.add("c");
        alist.add("d");
        alist.add("e");
        Iterator<String> it =  alist.iterator();
        //判断有没有下一个元素
        while(it.hasNext()){
            String item =  it.next();//取出元素
            if(item.equals("c")){
                it.remove();//使用迭代器提供的方法进行删除元素
            }
        }
        System.out.println(alist);
    }
}

五、Set 接口

不可以存储重复元素,添加时,会自定的判断,有的是无序,有的是有序的.

(一)HashSet

是无序的,既不按照添加顺序存放,也不按照内容自然顺序的存放
是调用hashCode()方法计算hash值,为了更快速的判断

但是只用hash判断,不安全,

要对hashCode方法进行重写

当hash值相同时,再调用equals()方法判断内容是否相同,保证了安全

import java.util.HashSet;

public class HashDemo2 {
    public static void main(String[] args) {
        /*
        HashSet添加元素时,是如何去除重复元素的.
		                判断元素是否重复时,没有直接使用equals()方法进行判断,因为equals()效率比较低.
		java中在比较是否重复时,先是调用hashCode(),计算出内容的hash值(整数),
		                   两个整数判断是否相等,是比较简单且快的,但是不同内容计算出来的hash值有可能相同,
		                   所以当hash值出现相同时,再调用equals()方法进行判断,
		                   这样既安全,又快速.
         */
        HashSet<String> hset = new HashSet<>();
        hset.add("a");
        hset.add("a");
        hset.add("通话");//1179410
        hset.add("重地");//1179410
        System.out.println(hset);
    }
}

(二)TreeSet

可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。

TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)

添加元素时,可以比较元素的大小, comparTo() 小于0 等于0 大于0

import java.util.TreeSet;

public class TreesetDemo1 {
    public static void main(String[] args) {
        /*
		  Set
		   TreeSet 不能存储重复元素
		   以按照值的自然顺序排序
		 */
        TreeSet<String> tset =  new TreeSet();
        tset.add("c");
        tset.add("b");
        tset.add("a");
        tset.add("d");
        tset.add("c");
        System.out.println(tset);
    }
}

import java.util.TreeSet;

public class TreesetDemo2 {
    public static void main(String[] args) {
        //向TreeSet中添加的元素的类,必须要实现Comparable接口,支持比较大小进行排序
        Car car1 = new Car(101, "宝马1");
        Car car2 = new Car(102, "宝马2");
        Car car3 = new Car(103, "宝马3");
        Car car4 = new Car(105, "宝马1");
        Car car5 = new Car(104, "宝马5");
        TreeSet<Car> tset =  new TreeSet();
        tset.add(car1);
        tset.add(car2);
        tset.add(car3);
        tset.add(car4);
        tset.add(car5);
        System.out.println(tset);
    }
}

六、Set 接口集合迭代

遍历方式: 因为set集合,元素没有索引,索引就不能使用普通的for
增强for循环
迭代器遍历 iterator();

与List迭代器类似

七、Map 接口

Map:
双列数据存储(键值对存储)
键–值
键值映射
键不能重复 值可以重复

每个键最多只能映射到一个值

(一)HashMap

HashMap中元素的key值不能重复,排列顺序是不固定的,可以存储一个为null的键.

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

public class HashMapDemo1 {
    public static void main(String[] args) {
		 /*
		    Map 键值对形式存储数据
		                    键不能重复,值可以重复
		    HashMap
		                    键是无序的,只能存储一个为null的键
		  */
        HashMap<String,String> map =  new HashMap();
        map.put("a","aa");
        map.put("z","ss");
        map.put("s","ss");
        map.put("h","hh");
        map.put("a","aaa");
        //map.clear();清空map中所有的键值
        //map.remove("a"); 删除指定的key
        System.out.println(map.get("h"));//通过key获取值
        System.out.println(map.containsKey("a"));//判断是否包含指定的key
        System.out.println(map.containsValue("ss"));//判断是否包含指定的value
        System.out.println(map.isEmpty());//判断是否为为空
        System.out.println(map.size());//键值对的数量

        Collection<String> list =  map.values();//获取值
        System.out.println(list);

        Set<String> keyset = map.keySet();//获取map中所有的key
        for(String key : keyset){
            String val  = map.get(key);
            System.out.println(key+"::"+val);
        }

        System.out.println(map);

    }
}
/*
hh
true
true
false
4
[aaa, ss, hh, ss]
a::aaa
s::ss
h::hh
z::ss
{a=aaa, s=ss, h=hh, z=ss}
*/

(二)TreeMap

TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序的Map就应该使用TreeMap,key值所在类必须实现Comparable接口.

(三)Hashtable

键值对存储

不能存储为null的key

Hashtable底层结构与HashMap类似

Hashtable是线程安全

(四)HashMap的底层结构

底层首先是数组:默认长度是16

比如要存储数据a—>ascll码97

进行一种运算(a%16,a&15)值(元素在数组中的位置,要保证在数组范围内)

首先底层是一个数组,用来确定元素在数组中的位置,数组长度只要使用率达到75%就会进行扩容(扩到原来的2倍),不会占满数组,否则查询效率会比较慢。

当存储一个元素时,首先会根据数据内容计算hash值,再用公式计算出在数组中的位置,然后在这个数组位置里再放入一个链表或者红黑树,链表长度等于8时转为红黑树。

(五)Map集合遍历

1.根据键找值

获取所有键的集合

遍历键的集合,获取到每一个键

根据键找值

2.根据键值对对象找键和值

获取所有键值对对象的集合

遍历键值对对象的集合,获取到每一个键值对对象

根据键值对对象找键和值

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

public class MapFor {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<>();
        map.put("a","a");
        map.put("b","b");
        map.put("z","ss");
        map.put("s","ss");
        map.put("h","hh");
        map.put("q","aaa");

        /*
        方式1:  keySet(); 获取map中 所有的key的集合
               变向的遍历map
        */
        Set<String> keyset  = map.keySet();
        for(String key : keyset){
            System.out.println(map.get(key));
        }

        /*
        方式2 : 在遍历时,将key-value元素,
               封装到一个个Entry对象中,
               Entry对象中包含了key和value
        */
        Set<Map.Entry<String,String>> entrySet = map.entrySet();
        for(Map.Entry<String,String> entry : entrySet){
            System.out.println(entry.getKey()+"::"+entry.getValue());
        }
    }
}
/*
a
aaa
b
ss
hh
ss
========方法一========方法二========
a::a
q::aaa
b::b
s::ss
h::hh
z::ss
*/

八、Collections类

Collection 接口 是单列集合的顶级接口
Collections类 提供了一些关于集合操作的方法,类似于Arrays类

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Demo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("c");
        list.add("d");
        list.add("b");
        System.out.println(list);//[a, c, d, b]
        Collections.addAll(list, "b","c","d");//在原来的列表的末尾添加新的元素
        System.out.println(list);//[a, c, d, b, b, c, d]
        System.out.println(Collections.binarySearch(list, "b")); //二分查找
        Collections.sort(list);//排序
        System.out.println(list);//[a, c, d, b, b, c, d]
        Collections.swap(list, 0, 3);//交换指定位置上的元素
        System.out.println(list);//[c, b, b, a, c, d, d]
        ArrayList<String> dest = new ArrayList<>();
        dest.add("1");
        dest.add("2");
        dest.add("3");
        dest.add("4");
        dest.add("5");
        dest.add("6");
        dest.add("7");
        dest.add("8");
        Collections.copy(dest, list);//把源数组复制到目标数组中,目标数组的size()大于等于源数组size(),源数组会覆盖新数组的对应位置的内容
        System.out.println(list);
        System.out.println(dest);
        List  emptyList =   Collections.emptyList();//返回一个空集合(内部类),不能使用,为了避免出现空指针
        //emptyList.add("1");//报错,emptyList不能使用,只用来返回一个空集合
        System.out.println(emptyList);//[]
        //Collections.fill(list,"+");//用指定内容填充集合  会覆盖新数组的对应位置的内容
        //System.out.println(list);[+,+,+,+,+,+,+]
        Collections.reverse(list);//逆序
        System.out.println(list);//[d, d, c, a, b, b, c]
        Collections.shuffle(list);//随机调整元素的位置
        System.out.println(list);
        System.out.println(Collections.max(list));//返回最大的元素d
        //int...a可变长度参数  本质是一个数组  在一个参数列表中,只能有一个可变长度的参数,并且只能放在参数列表的最后面
        Demo.test(1,2,3);
    }
    public static void test(int b,int...a){
        System.out.println(Arrays.toString(a));
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值