java-集合

什么是算法和数据结构

【1】算法:

(1)可以解决具体问题 :例如   1+2+3+4+。。。+99+100

解题流程=算法

(2)有设计解决的具体的流程

算法1: 1+2=3  3+3=6 6+4=10.....加到100  --》5050

算法2:(1+100)*50=101*50=5050-->高斯算法

(3)有评价这个算法的具体的指标 --》时间复杂度  空间复杂度(从数学角度考虑)

---------------------------------------------------------------------

【2】数据结构就是在计算机的缓存,内存,硬盘  如何组织管理数据的。重点在结构上,是按照什么结构来组织管理我们的数据。

数据结构分为:

(1)逻辑结构 :--》思想上的结构--》卧室,厨房,卫生间 ---》线性表(数组,链表),图,树,栈,队列

(2)物理结构 :--》真实结构--》钢筋混凝土+牛顿力学------》紧密结构(顺序结构),跳转结构(链式结构)

【3】紧密结构(顺序结构),跳转结构(链式结构) 

以线性表为例: 

线性表的逻辑结构如图所示:

线性表特点: 

线性表是n个类型相同数据元素的有限序列,通常记作a0,a1,,,ai-1,ai,ai+1,,,,,an-1)。

1.相同数据类型 

  在线性表的定义中,我们看到从a0到an-1的n个数据元素是具有相同属件的亓素。

  比如说可以都是数字,例如(12,23,45,56,45);

  也可以是宇符,例如(A,B,....Z)

  当然也可以是具有更复杂结构的数据元素,例如学生、商品、装备等。

  相同数据类型意味着在内存中存储时,每个元素会占用相同的内存空间,便于后续的查询定位。

2.序列(顺序性) 

  在线性表的相邻数据元素之间存在若序偶关系,

  即ai-1是ai的直接前驱,则ai是ai-1的直接后续,

  同时ai又是ai+1的直接前驱,ai+1是ai的直接后续。

  唯一没有直接前驱的元素a0 一端称为表头,唯一没有后续的元素an-1一端称为表尾。

  除了表头和表尾元素外,任何一个元素都有且仅有一个直接前驱和直接后继。

3.有限 

  线件表中数据元素的个数n定义为线性表的长度, n是个有限值。

  当n=0时线性表为空表,

  在非空的线性表中每个数据元索在线性表中都有唯一确定的序号,

  例如a0的序号是0 ,ai的序号是i。

  在一个具有n>0个数据元素的线性表中,数据元素序号的范围是[O, n-1]。

 逻辑结构和物理结构的关系: 

线性表逻辑结构,对应的真实结构如果是紧密结构---》典型就是  数组:

线性表逻辑结构,对应的真实结构如果是跳转结构---》典型就是  链表:

优点:删除元素,插入元素效率高

缺点:查询元素效率低

集合的引入

【1】数组,集合都是对多个数据进行存储操作的,简称为容器。

PS:这里的存储指的是内存层面的存储,而不是持久化存储(.txt,.avi,.jpg,数据库)。

【2】数组:特点:

(1)数组一旦指定了长度,那么长度就被确定了,不可以更改。

int[] arr = new int[6];

(2)数组一旦声明了类型以后,数组中只能存放这个类型的数据。数组中只能

存放同一种类型的数据。

int[] arr,String[] s,double[] d.....

【3】数组:缺点:

(1)数组一旦指定了长度,那么长度就被确定了,不可以更改。

(2)删除,增加元素  效率低。

(3)数组中实际元素的数量是没有办法获取的,没有提供对应的方法或者属性来获取

(4)数组存储:有序,可重复 ,对于无序的,不可重复的数组不能满足要求。

【4】正因为上面的缺点,引入了一个新的存储数据的结构---》集合

【5】集合一章我们会学习很多集合,为什么要学习这么多集合呢?

因为不同集合底层数据结构不一样。集合不一样,特点也不一样

简要集合结构图

集合应用场合

前端后端数据库交互:

当需要将相同结构的个体整合到一起的时候,需要集合。

实际应用场合:

Colletion接口

Colletion接口常用方法

1.package com.msb.test01;
2.
3.import java.util.ArrayList;
4.import java.util.Arrays;
5.import java.util.Collection;
6.import java.util.List;
7.
8./**
9. * @author : msb-zhaoss
10. */
11.public class Test01 {
12.    //这是main方法,程序的入口
13.    public static void main(String[] args) {
14.        /*
15.        Collection接口的常用方法:
16.        增加:add(E e) addAll(Collection<? extends E> c)
17.        删除:clear() remove(Object o)
18.        修改:
19.        查看:iterator() size()
20.        判断:contains(Object o)  equals(Object o) isEmpty()
21.         */
22.        //创建对象:接口不能创建对象,利用实现类创建对象:
23.        Collection col = new ArrayList();
24.        //调用方法:
25.        //集合有一个特点:只能存放引用数据类型的数据,不能是基本数据类型
26.        //基本数据类型自动装箱,对应包装类。int--->Integer
27.        col.add(18);
28.        col.add(12);
29.        col.add(11);
30.        col.add(17);
31.
32.        System.out.println(col/*.toString()*/);
33.
34.        List list = Arrays.asList(new Integer[]{11, 15, 3, 7, 1});
35.        col.addAll(list);//将另一个集合添加入col中
36.        System.out.println(col);
37.
38.        //col.clear();清空集合
39.        System.out.println(col);
40.        System.out.println("集合中元素的数量为:"+col.size());
41.        System.out.println("集合是否为空:"+col.isEmpty());
42.
43.        boolean isRemove = col.remove(15);
44.        System.out.println(col);
45.        System.out.println("集合中数据是否被删除:"+isRemove);
46.
47.
48.        Collection col2 = new ArrayList();
49.        col2.add(18);
50.        col2.add(12);
51.        col2.add(11);
52.        col2.add(17);
53.
54.        Collection col3 = new ArrayList();
55.        col3.add(18);
56.        col3.add(12);
57.        col3.add(11);
58.        col3.add(17);
59.
60.        System.out.println(col2.equals(col3));
61.        System.out.println(col2==col3);//地址一定不相等  false
62.
63.        System.out.println("是否包含元素:"+col3.contains(117));
64.
65.    }
66.}

Collection集合的遍历

迭代器简要原理图:

1.package com.msb.test01;
2.
3.import java.util.ArrayList;
4.import java.util.Collection;
5.import java.util.Iterator;
6.
7./**
8. * @author : msb-zhaoss
9. */
10.public class Test02 {
11.    //这是main方法,程序的入口
12.    public static void main(String[] args) {
13.        Collection col = new ArrayList();
14.        col.add(18);
15.        col.add(12);
16.        col.add(11);
17.        col.add(17);
18.        col.add("abc");
19.        col.add(9.8);
20.
21.        //对集合遍历(对集合中元素进行查看)
22.        //方式1:普通for循环
23.        /*for(int i= 0;i<col.size();i++){
24.            col.
25.        }*/
26.
27.        //方式2:增强for循环
28.        for(Object o:col){
29.            System.out.println(o);
30.        }
31.        System.out.println("------------------------");
32.        //方式3:iterator()
33.        Iterator it = col.iterator();
34.        while(it.hasNext()){
35.            System.out.println(it.next());
36.        }
37.    }
38.}

List接口

List接口的常用方法和遍历方式
1.package com.msb.test01;
2.
3.import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;
4.
5.import java.util.ArrayList;
6.import java.util.Iterator;
7.import java.util.List;
8.
9./**
10. * @author : msb-zhaoss
11. */
12.public class Test03 {
13.    //这是main方法,程序的入口
14.    public static void main(String[] args) {
15.        /*
16.        List接口中常用方法:
17.        增加:add(int index, E element)
18.        删除:remove(int index)  remove(Object o)
19.        修改:set(int index, E element)
20.        查看:get(int index)
21.        判断:
22.         */
23.        List list = new ArrayList();
24.        list.add(13);
25.        list.add(17);
26.        list.add(6);
27.        list.add(-1);
28.        list.add(2);
29.        list.add("abc");
30.        System.out.println(list);
31.        list.add(3,66);
32.        System.out.println(list);
33.        list.set(3,77);
34.        System.out.println(list);
35.        list.remove(2);//在集合中存入的是Integer类型数据的时候,调用remove方法调用的是:remove(int index)
36.        System.out.println(list);
37.        list.remove("abc");
38.        System.out.println(list);
39.
40.        Object o = list.get(0);
41.        System.out.println(o);
42.
43.        //List集合 遍历:
44.        //方式1:普通for循环:
45.        System.out.println("---------------------");
46.        for(int i = 0;i<list.size();i++){
47.            System.out.println(list.get(i));
48.        }
49.        //方式2:增强for循环:
50.        System.out.println("---------------------");
51.        for(Object obj:list){
52.            System.out.println(obj);
53.        }
54.        //方式3:迭代器:
55.        System.out.println("---------------------");
56.        Iterator it = list.iterator();
57.        while(it.hasNext()){
58.            System.out.println(it.next());
59.        }
60.
61.
62.    }
63.}
ArrayList实现类(JDK1.7)

【1】在idea中切换JDK的方法:

【2】ArrayList实现List接口的失误:

集合创始人 承认了这个失误,但是在后续的版本中没有删除,觉得没必要:

【3】底层重要属性:

在JDK1.7中:在调用构造器的时候给底层数组elementData初始化,数组初始化长度为10:

对应内存:

调用add方法:

1.  ArrayList al = new ArrayList();
2.
3.        System.out.println(al.add("abc"));System.out.println(al.add("def"));

当数组中的10个位置都满了的时候就开始进行数组的扩容,扩容长度为 原数组的1.5倍:

ArrayList实现类(JDK1.8)

【1】JDK1.8底层依旧是Object类型的数组,size:数组中有效长度:

【2】ArrayList al = new ArrayList();调用空构造器:

【2】add方法:

Vector实现类

【1】底层Object数组,int类型属性表示数组中有效长度:

【2】Vector v=new Vector();调用构造器:

【3】add方法:

泛型
引入

【1】什么是泛型(Generic):

泛型就相当于标签

形式:<>  

集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,

JDK1.5之 后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。

Collection<E>, List<E>, ArrayList<E> 这个<E>就是类型参数,即泛型。

【2】没有泛型的时候使用集合:

1.package com.msb.test01;
2.
3.import java.util.ArrayList;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Test01 {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个ArrayList集合,向这个集合中存入学生的成绩:
12.        ArrayList al = new ArrayList();
13.        al.add(98);
14.        al.add(18);
15.        al.add(39);
16.        al.add(60);
17.        al.add(83);
18.        al.add("丽丽");
19.
20.        //对集合遍历查看:
21.        for(Object obj:al){
22.            System.out.println(obj);
23.        }
24.    }
25.}

如果不使用泛型的话,有缺点:

一般我们在使用的时候基本上往集合中存入的都是相同类型的数据--》便于管理,所以现在什么引用数据类型都可以存入集合,不方便!

【3】JDK1.5以后开始使用泛型,集合中使用泛型:

1.package com.msb.test01;
2.
3.import java.util.ArrayList;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Test01 {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个ArrayList集合,向这个集合中存入学生的成绩:
12.        //加入泛型的优点:在编译时期就会对类型进行检查,不是泛型对应的类型就不可以添加入这个集合。
13.        ArrayList<Integer> al = new ArrayList<Integer>();
14.        al.add(98);
15.        al.add(18);
16.        al.add(39);
17.        al.add(60);
18.        al.add(83);
19.        /*al.add("丽丽");
20.        al.add(9.8);*/
21.
22.        //对集合遍历查看:
23.        /*for(Object obj:al){
24.            System.out.println(obj);
25.        }*/
26.        for(Integer i:al){
27.            System.out.println(i);
28.        }
29.    }
30.}

【4】泛型总结:

(1)JDK1.5以后

(2)泛型实际就是 一个<>引起来的 参数类型,这个参数类型  具体在使用的时候才会确定具体的类型。 

(3)使用了泛型以后,可以确定集合中存放数据的类型,在编译时期就可以检查出来。

(4)使用泛型你可能觉得麻烦,实际使用了泛型才会简单,后续的遍历等操作简单。

(5)泛型的类型:都是引用数据类型,不能是基本数据类型。

(6)ArrayList<Integer> al = new ArrayList<Integer>();在JDK1.7以后可以写为:

ArrayList<Integer> al = new ArrayList<>();  --<>  ---钻石运算符

自定义泛型结构

泛型类,泛型接口

【1】泛型类的定义和实例化:

1.package com.msb.test02;
2.
3./**
4. * @author : msb-zhaoss
5. * GenericTes就是一个普通的类
6. * GenericTest<E> 就是一个泛型类
7. * <>里面就是一个参数类型,但是这个类型是什么呢?这个类型现在是不确定的,相当于一个占位
8. * 但是现在确定的是这个类型一定是一个引用数据类型,而不是基本数据类型
9. */
10.public class GenericTest<E> {
11.    int age;
12.    String name;
13.    E sex;
14.
15.    public void a(E n){
16.
17.    }
18.    public void b(E[] m){
19.
20.    }
21.}
22.
23.class Test{
24.    //这是main方法,程序的入口
25.    public static void main(String[] args) {
26.        //GenericTest进行实例化:
27.        //(1)实例化的时候不指定泛型:如果实例化的时候不明确的指定类的泛型,那么认为此泛型为Object类型
28.        GenericTest gt1 = new GenericTest();
29.        gt1.a("abc");
30.        gt1.a(17);
31.        gt1.a(9.8);
32.        gt1.b(new String[]{"a","b","c"});
33.
34.        //(2)实例化的时候指定泛型:---》推荐方式
35.        GenericTest<String> gt2 = new GenericTest<>();
36.        gt2.sex = "男";
37.        gt2.a("abc");
38.        gt2.b(new String[]{"a","b","c"});
39.        
40.    }
41.}

【2】继承情况:

(1)父类指定泛型

1.class SubGenericTest extends GenericTest<Integer>{
2.
3.}
4.
5.class Demo{
6.    //这是main方法,程序的入口
7.    public static void main(String[] args) {
8.        //指定父类泛型,那么子类就不需要再指定泛型了,可以直接使用
9.        SubGenericTest sgt = new SubGenericTest();
10.        sgt.a(19);
11.    }
12.}

(2)父类不指定泛型:

如果父类不指定泛型,那么子类也会变成一个泛型类,那这个E的类型可以在创建子类对象的时候确定:

1.class SubGenericTest2<E> extends GenericTest<E>{
2.
3.}1.class Demo2{
2.    //这是main方法,程序的入口
3.    public static void main(String[] args) {
4.        SubGenericTest2<String> s = new  SubGenericTest2<>();
5.        s.a("abc");
6.        s.sex = "女";
7.    }
8.}

【3】应用场合:

【4】细节:

(1)泛型类可以定义多个参数类型

(2)泛型类的构造器的写法:

(3)不同的泛型的引用类型不可以相互赋值:

(4)泛型如果不指定,那么就会被擦除,反应对应的类型为Object类型:

(5)反省类中的静态方法不能使用类的泛型:

(6)不能直接使用E[]的创建:

泛型方法
1.package com.msb.test04;
2.
3./**
4. * @author : msb-zhaoss
5. * 1.什么是泛型方法:
6. * 不是带泛型的方法就是泛型方法
7. * 泛型方法有要求:这个方法的泛型的参数类型要和当前的类的泛型无关
8. * 换个角度:
9. * 泛型方法对应的那个泛型参数类型 和  当前所在的这个类 是否是泛型类,泛型是啥  无关
10. * 2.泛型方法定义的时候,前面要加上<T>
11. *     原因:如果不加的话,会把T当做一种数据类型,然而代码中没有T类型那么就会报错
12. * 3.T的类型是在调用方法的时候确定的
13. * 4.泛型方法可否是静态方法?可以是静态方法
14. */
15.public class TestGeneric<E> {
16.    //不是泛型方法 (不能是静态方法)
17.    public static void a(E e){
18.
19.    }
20.    //是泛型方法
21.    public static <T>  void b(T t){
22.
23.    }
24.
25.}
26.class Demo{
27.    //这是main方法,程序的入口
28.    public static void main(String[] args) {
29.        TestGeneric<String> tg = new TestGeneric<>();
30.        tg.a("abc");
31.        tg.b("abc");
32.        tg.b(19);
33.        tg.b(true);
34.    }
35.}
36.
泛型参数存在继承关系的情况

通配符

【1】在没有通配符的时候:

下面的a方法,相当于方法的重复定义,报错

1.public class Test {
2.    /*public void a(List<Object> list){
3.
4.    }
5.    public void a(List<String> list){
6.
7.    }
8.    public void a(List<Integer> list){
9.
10.    }*/
}

【2】引入通配符:

1.public class Demo {
2.    //这是main方法,程序的入口
3.    public static void main(String[] args) {
4.        List<Object> list1 = new ArrayList<>();
5.        List<String> list2 = new ArrayList<>();
6.        List<Integer> list3 = new ArrayList<>();
7.
8.        List<?> list = null;
9.        list = list1;
10.        list = list2;
11.        list = list3;
12.
13.    }
14.}

发现: A 和 B是子类父类的关系,G<A>和G<B>不存在子类父类关系,是并列的

加入通配符?后,G<?>就变成了 G<A>和G<B>的父类

【3】使用通配符:

1.package com.msb.test06;
2.
3.import java.util.ArrayList;
4.import java.util.List;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test {
10.    /*public void a(List<Object> list){
11.
12.    }
13.    public void a(List<String> list){
14.
15.    }
16.    public void a(List<Integer> list){
17.
18.    }*/
19.    public void a(List<?> list){
20.        //内部遍历的时候用Object即可,不用?
21.        for(Object a:list){
22.            System.out.println(a);
23.        }
24.    }
25.}
26.
27.class T{
28.    //这是main方法,程序的入口
29.    public static void main(String[] args) {
30.        Test t = new Test();
31.        t.a(new ArrayList<Integer>());
32.        t.a(new ArrayList<String>());
33.        t.a(new ArrayList<Object>());
34.    }
35.}

【4】查看API中应用位置:

使用通配符后的细节
1.public class Test {
2.    public void a(List<?> list){
3.        //1.遍历:
4.        for(Object a:list){
5.            System.out.println(a);
6.        }
7.        //2.数据的写入操作 :
8.        //list.add("abc");-->出错,不能随意的添加数据
9.        list.add(null);
10.
11.        //3.数据的读取操作:
12.        Object s = list.get(0);
13.    }
14.}
15.
16.class T{
17.    //这是main方法,程序的入口
18.    public static void main(String[] args) {
19.        Test t = new Test();
20.        t.a(new ArrayList<Integer>());
21.        t.a(new ArrayList<String>());
22.        t.a(new ArrayList<Object>());
23.    }
24.}

泛型受限
1.package com.msb.test07;
2.
3.import java.util.ArrayList;
4.import java.util.List;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test {
10.    //这是main方法,程序的入口
11.    public static void main(String[] args) {
12.        //a,b,c三个集合是并列的关系:
13.        List<Object> a = new ArrayList<>();
14.        List<Person> b = new ArrayList<>();
15.        List<Student> c = new ArrayList<>();
16.        /*开始使用泛型受限:泛型的上限
17.        List<? extends Person>:
18.        就相当于:
19.        List<? extends Person>是List<Person>的父类,是List<Person的子类>的父类
20.         */
21.        List<? extends Person> list1 = null;
22.        /*list1 = a;
23.        list1 = b;
24.        list1 = c;*/
25.        /*开始使用泛型受限:泛型的下限
26.        List<? super Person>
27.        就相当于:
28.        List<? super Person>是List<Person>的父类,是List<Person的父类>的父类
29.         */
30.        List<? super Person> list2 = null;
31.        list2 = a;
32.        list2 = b;
33.        list3 = c;
34.    }
35.}
LinkedList实现类的使用
1.package com.msb.test04;
2.
3.import java.util.Iterator;
4.import java.util.LinkedList;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test {
10.    //这是main方法,程序的入口
11.    public static void main(String[] args) {
12.        /*
13.        LinkedList常用方法:
14.        增加 addFirst(E e) addLast(E e)
15.             offer(E e) offerFirst(E e) offerLast(E e)
16.        删除 poll()
17.            pollFirst() pollLast()  ---》JDK1.6以后新出的方法,提高了代码的健壮性
18.            removeFirst() removeLast()
19.        修改
20.        查看 element()
21.             getFirst()  getLast()
22.             indexOf(Object o)   lastIndexOf(Object o)
23.             peek()
24.             peekFirst() peekLast()
25.        判断
26.         */
27.        //创建一个LinkedList集合对象:
28.        LinkedList<String> list = new LinkedList<>();
29.        list.add("aaaaa");
30.        list.add("bbbbb");
31.        list.add("ccccc");
32.        list.add("ddddd");
33.        list.add("eeeee");
34.        list.add("bbbbb");
35.        list.add("fffff");
36.
37.        list.addFirst("jj");
38.        list.addLast("hh");
39.
40.        list.offer("kk");//添加元素在尾端
41.        list.offerFirst("pp");
42.        list.offerLast("rr");
43.        System.out.println(list);//LinkedList可以添加重复数据
44.        System.out.println(list.poll());//删除头上的元素并且将元素输出
45.        System.out.println(list.pollFirst());
46.        System.out.println(list.pollLast());
47.
48.        System.out.println(list.removeFirst());
49.        System.out.println(list.removeLast());
50.        System.out.println(list);//LinkedList可以添加重复数据
51.
52.        /*list.clear();//清空集合
53.        System.out.println(list);*/
54.        /*System.out.println(list.pollFirst());*/
55.        /*System.out.println(list.removeFirst());报错:Exception in thread "main" java.util.NoSuchElementException*/
56.
57.
58.        //集合的遍历:
59.        System.out.println("---------------------");
60.        //普通for循环:
61.        for(int i = 0;i<list.size();i++){
62.            System.out.println(list.get(i));
63.        }
64.        System.out.println("---------------------");
65.        //增强for:
66.        for(String s:list){
67.            System.out.println(s);
68.        }
69.        System.out.println("---------------------");
70.        //迭代器:
71.        /*Iterator<String> it = list.iterator();
72.        while(it.hasNext()){
73.            System.out.println(it.next());
74.        }*/
75.        //下面这种方式好,节省内存
76.        for(Iterator<String> it = list.iterator();it.hasNext();){
77.            System.out.println(it.next());
78.        }
79.    }
80.}
LinkedList简要底层原理图

模拟LinkedList源码
1.package com.msb.test05;
2.
3./**
4. * @author : msb-zhaoss
5. */
6.public class MyLinkedList {
7.    //链中一定有一个首节点:
8.    Node first;
9.    //链中一定有一个尾节点:
10.    Node last;
11.    //计数器:
12.    int count = 0;
13.    //提供一个构造器:
14.    public MyLinkedList(){
15.
16.    }
17.    //添加元素方法:
18.    public void add(Object o){
19.        if(first == null){//证明你添加的元素是第一个节点:
20.            //将添加的元素封装为一个Node对象:
21.            Node n = new Node();
22.            n.setPre(null);
23.            n.setObj(o);
24.            n.setNext(null);
25.            //当前链中第一个节点变为n
26.            first = n;
27.            //当前链中最后一个节点变为n
28.            last = n;
29.        }else{//证明已经不是链中第一个节点了
30.            //将添加的元素封装为一个Node对象:
31.            Node n = new Node();
32.            n.setPre(last);//n的上一个节点一定是当前链中的最后一个节点last
33.            n.setObj(o);
34.            n.setNext(null);
35.            //当前链中的最后一个节点的下一个元素 要指向n
36.            last.setNext(n);
37.            //将最后一个节点变为n
38.            last = n;
39.        }
40.        //链中元素数量加1
41.        count++;
42.    }
43.
44.    //得到集合中元素的数量:
45.    public int getSize(){
46.        return count;
47.    }
48.
49.    //通过下标得到元素:
50.    public Object get(int index){
51.        //获取链表的头元素:
52.        Node n = first;
53.        //一路next得到想要的元素
54.        for(int i=0;i<index;i++){
55.            n = n.getNext();
56.        }
57.        return n.getObj();
58.    }
59.}
60.class Test{
61.    //这是main方法,程序的入口
62.    public static void main(String[] args) {
63.        //创建一个MyLinkedList集合对象:
64.        MyLinkedList ml = new MyLinkedList();
65.        ml.add("aa");
66.        ml.add("bb");
67.        ml.add("cc");
68.        System.out.println(ml.getSize());
69.        System.out.println(ml.get(0));
70.    }
71.}

debug验证数据添加成功:

LinkedList源码解析

【1】JDK1.7和JDK1.8的LinkedList的源码是一致的

【2】源码:

1.public class LinkedList<E>{//E是一个泛型,具体的类型要在实例化的时候才会最终确定
2.        transient int size = 0;//集合中元素的数量
3.        //Node的内部类
4.        private static class Node<E> {
5.        E item;//当前元素
6.        Node<E> next;//指向下一个元素地址
7.        Node<E> prev;//上一个元素地址
8.
9.        Node(Node<E> prev, E element, Node<E> next) {
10.            this.item = element;
11.            this.next = next;
12.            this.prev = prev;
13.        }
14.    }
15.
16.        transient Node<E> first;//链表的首节点
17.        transient Node<E> last;//链表的尾节点
18.        //空构造器:
19.        public LinkedList() {
20.    }
21.        //添加元素操作:
22.        public boolean add(E e) {
23.        linkLast(e);
24.        return true;
25.    }
26.        void linkLast(E e) {//添加的元素e
27.        final Node<E> l = last;//将链表中的last节点给l 如果是第一个元素的话 l为null
28.                //将元素封装为一个Node具体的对象:
29.        final Node<E> newNode = new Node<>(l, e, null);
30.                //将链表的last节点指向新的创建的对象:
31.        last = newNode;
32.                
33.        if (l == null)//如果添加的是第一个节点
34.            first = newNode;//将链表的first节点指向为新节点
35.        else//如果添加的不是第一个节点 
36.            l.next = newNode;//将l的下一个指向为新的节点
37.        size++;//集合中元素数量加1操作
38.        modCount++;
39.    }
40.        //获取集合中元素数量
41.        public int size() {
42.        return size;
43.    }
44.        //通过索引得到元素:
45.        public E get(int index) {
46.        checkElementIndex(index);//健壮性考虑
47.        return node(index).item;
48.    }
49.        
50.    Node<E> node(int index) {
51.        //如果index在链表的前半段,那么从前往后找
52.
53.        if (index < (size >> 1)) {
54.            Node<E> x = first;
55.            for (int i = 0; i < index; i++)
56.                x = x.next;
57.            return x;
58.        } else {//如果index在链表的后半段,那么从后往前找
59.            Node<E> x = last;
60.            for (int i = size - 1; i > index; i--)
61.                x = x.prev;
62.            return x;
63.        }
64.    }
65.
66.}
面试题:iterator(),Iterator,Iterable关系

【1】面试题:对应的关系:

【2】hasNext(),next()的具体实现:

【3】增强for循环  底层也是通过迭代器实现的:

ListIterator迭代器

【1】加入字符串:

1.package com.msb.test06;
2.
3.import java.util.ArrayList;
4.import java.util.Iterator;
5.import java.util.List;
6.
7./**
8. * @author : msb-zhaoss
9. */
10.public class Test2 {
11.    //这是main方法,程序的入口
12.    public static void main(String[] args) {
13.        ArrayList<String> list = new ArrayList<>();
14.        list.add("aa");
15.        list.add("bb");
16.        list.add("cc");
17.        list.add("dd");
18.        list.add("ee");
19.        //在"cc"之后添加一个字符串"kk"
20.        Iterator<String> it = list.iterator();
21.        while(it.hasNext()){
22.            if("cc".equals(it.next())){
23.                list.add("kk");
24.            }
25.        }
26.
27.    }
28.}

发现报错:

出错原因:就是迭代器和list同时对集合进行操作:

解决办法:事情让一个“人”做 --》引入新的迭代器:ListIterator

迭代和添加操作都是靠ListIterator来完成的:

1.package com.msb.test06;
2.
3.import java.util.ArrayList;
4.import java.util.Iterator;
5.import java.util.List;
6.import java.util.ListIterator;
7.
8./**
9. * @author : msb-zhaoss
10. */
11.public class Test2 {
12.    //这是main方法,程序的入口
13.    public static void main(String[] args) {
14.        ArrayList<String> list = new ArrayList<>();
15.        list.add("aa");
16.        list.add("bb");
17.        list.add("cc");
18.        list.add("dd");
19.        list.add("ee");
20.        //在"cc"之后添加一个字符串"kk"
21.        ListIterator<String> it = list.listIterator();
22.        while(it.hasNext()){
23.            if("cc".equals(it.next())){
24.                it.add("kk");
25.            }
26.        }
27.        System.out.println(it.hasNext());
28.        System.out.println(it.hasPrevious());
29.        //逆向遍历:
30.        while(it.hasPrevious()){
31.            System.out.println(it.previous());
32.        }
33.        System.out.println(it.hasNext());
34.        System.out.println(it.hasPrevious());
35.        System.out.println(list);
36.
37.    }
38.}

Set接口

HashSet实现类的使用

【1】放入Integer类型数据:

1.package com.msb.test07;
2.
3.import java.util.HashSet;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class TestInteger {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个HashSet集合:
12.        HashSet<Integer> hs = new HashSet<>();
13.        System.out.println(hs.add(19));//true
14.        hs.add(5);
15.        hs.add(20);
16.        System.out.println(hs.add(19));//false 这个19没有放入到集合中
17.        hs.add(41);
18.        hs.add(0);
19.        System.out.println(hs.size());//唯一,无序
20.        System.out.println(hs);
21.
22.    }
23.}
24.

【2】放入String类型数据:

1.package com.msb.test07;
2.
3.import java.util.HashSet;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class TestString {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个HashSet集合:
12.        HashSet<String> hs = new HashSet<>();
13.        hs.add("hello");
14.        hs.add("apple");
15.        hs.add("banana");
16.        hs.add("html");
17.        hs.add("apple");
18.        hs.add("css");
19.        System.out.println(hs.size());
20.        System.out.println(hs);
21.    }
22.}

【3】放入自定义的引用数据类型的数据:

1.package com.msb.test07;
2.
3.import java.util.HashSet;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class TestStudent {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个HashSet集合:
12.        HashSet<Student> hs = new HashSet<>();
13.        hs.add(new Student(19,"lili"));
14.        hs.add(new Student(20,"lulu"));
15.        hs.add(new Student(18,"feifei"));
16.        hs.add(new Student(19,"lili"));
17.        hs.add(new Student(10,"nana"));
18.        System.out.println(hs.size());
19.        System.out.println(hs);
20.    }
21.}

上面自定义的类型不满足 唯一,无序的特点。为什么呢?

【4】HashSet原理图:(简要原理图)

【5】疑问:

1.数组的长度是多少。

2.数组的类型是什么?

3.hashCode,equals方法真的调用了吗?验证

4.底层表达式是什么?

5.同一个位置的数据 向前放  还是 向后放?

6.放入数组中的数据,是直接放的吗?是否封装为对象了?

LinkedHashSet使用

其实就是在HashSet的基础上,多了一个总的链表,这个总链表将放入的元素串在一起,方便有序的遍历:

可以看到LinkedHashMap.Entry 继承自HashMap.Node 除了Node 本身有的几个属性外,额外增加了before after 用于指向前一个Entry 后一个Entry。也就是说,元素之间维持着一条总的链表数据结构。

代码:

1.package com.msb.test07;
2.
3.import java.util.HashSet;
4.import java.util.LinkedHashMap;
5.import java.util.LinkedHashSet;
6.
7./**
8. * @author : msb-zhaoss
9. */
10.public class TestInteger {
11.    //这是main方法,程序的入口
12.    public static void main(String[] args) {
13.        //创建一个HashSet集合:
14.        LinkedHashSet<Integer> hs = new LinkedHashSet<>();
15.        System.out.println(hs.add(19));//true
16.        hs.add(5);
17.        hs.add(20);
18.        System.out.println(hs.add(19));//false 这个19没有放入到集合中
19.        hs.add(41);
20.        hs.add(0);
21.        System.out.println(hs.size());//唯一,无序
22.        System.out.println(hs);
23.    }
24.}
25.
比较器的使用

【1】以int类型为案例:

比较的思路:将比较的数据做差,然后返回一个int类型的数据,将这个int类型的数值  按照 =0  >0  <0

1.int a = 10;
2.        int b = 20;
3.        System.out.println(a-b); // =0  >0  <0

【2】比较String类型数据:

String类实现了Comparable接口,这个接口中有一个抽象方法compareTo,String类中重写这个方法即可

1.String a = "A";
2.        String b = "B";System.out.println(a.compareTo(b));

【3】比较double类型数据:

1.double a = 9.6;
2.        double b = 9.3;
3.       /* System.out.println((int)(a-b));*/
4.        System.out.println(((Double) a).compareTo((Double) b));

【4】比较自定义的数据类型:

(1)内部比较器:

1.package com.msb.test08;
2.
3./**
4. * @author : msb-zhaoss
5. */
6.public class Student implements Comparable<Student>{
7.    private int age;
8.    private double height;
9.    private String name;
10.
11.    public int getAge() {
12.        return age;
13.    }
14.
15.    public void setAge(int age) {
16.        this.age = age;
17.    }
18.
19.    public double getHeight() {
20.        return height;
21.    }
22.
23.    public void setHeight(double height) {
24.        this.height = height;
25.    }
26.
27.    public String getName() {
28.        return name;
29.    }
30.
31.    public void setName(String name) {
32.        this.name = name;
33.    }
34.
35.    public Student(int age, double height, String name) {
36.        this.age = age;
37.        this.height = height;
38.        this.name = name;
39.    }
40.
41.    @Override
42.    public String toString() {
43.        return "Student{" +
44.                "age=" + age +
45.                ", height=" + height +
46.                ", name='" + name + '\'' +
47.                '}';
48.    }
49.
50.    @Override
51.    public int compareTo(Student o) {
52.        //按照年龄进行比较:
53.        /*return this.getAge() - o.getAge();*/
54.        //按照身高比较
55.        /*return ((Double)(this.getHeight())).compareTo((Double)(o.getHeight()));*/
56.        //按照名字比较:
57.        return this.getName().compareTo(o.getName());
58.    }
59.}
1.package com.msb.test08;
2.
3./**
4. * @author : msb-zhaoss
5. */
6.public class Test02 {
7.    //这是main方法,程序的入口
8.    public static void main(String[] args) {
9.        //比较两个学生:
10.        Student s1 = new Student(14,160.5,"alili");
11.        Student s2 = new Student(14,170.5,"bnana");
12.        System.out.println(s1.compareTo(s2));
13.    }
14.}
15.

(2)外部比较器:

1.package com.msb.test09;
2.
3.import java.util.Comparator;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Student{
9.    private int age;
10.    private double height;
11.    private String name;
12.
13.    public int getAge() {
14.        return age;
15.    }
16.
17.    public void setAge(int age) {
18.        this.age = age;
19.    }
20.
21.    public double getHeight() {
22.        return height;
23.    }
24.
25.    public void setHeight(double height) {
26.        this.height = height;
27.    }
28.
29.    public String getName() {
30.        return name;
31.    }
32.
33.    public void setName(String name) {
34.        this.name = name;
35.    }
36.
37.    public Student(int age, double height, String name) {
38.        this.age = age;
39.        this.height = height;
40.        this.name = name;
41.    }
42.
43.    @Override
44.    public String toString() {
45.        return "Student{" +
46.                "age=" + age +
47.                ", height=" + height +
48.                ", name='" + name + '\'' +
49.                '}';
50.    }
51.
52.
53.}
54.
55.
56.
57.class BiJiao01 implements Comparator<Student> {
58.    @Override
59.    public int compare(Student o1, Student o2) {
60.        //比较年龄:
61.        return o1.getAge()-o2.getAge();
62.    }
63.}
64.
65.class BiJiao02 implements Comparator<Student> {
66.    @Override
67.    public int compare(Student o1, Student o2) {
68.        //比较姓名:
69.        return o1.getName().compareTo(o2.getName());
70.    }
71.}
1.class BiJiao03 implements Comparator<Student> {
2.    @Override
3.    public int compare(Student o1, Student o2) {
4.        //在年龄相同的情况下 比较身高  年龄不同比较年龄
5.        if((o1.getAge()-o2.getAge())==0){
6.            return ((Double)(o1.getHeight())).compareTo((Double)(o2.getHeight()));
7.        }else{//年龄不一样
8.            return o1.getAge()-o2.getAge();
9.        }
10.    }
11.}
1.package com.msb.test09;
2.
3.import com.msb.test09.Student;
4.
5.import java.util.Comparator;
6.
7./**
8. * @author : msb-zhaoss
9. */
10.public class Test02 {
11.    //这是main方法,程序的入口
12.    public static void main(String[] args) {
13.        //比较两个学生:
14.        Student s1 = new Student(9,160.5,"alili");
15.        Student s2 = new Student(14,170.5,"bnana");
16.        //获取外部比较器:
17.        Comparator bj1 = new BiJiao03();
18.        System.out.println(bj1.compare(s1, s2));
19.    }
20.}

【5】外部比较器和内部比较器 谁好呀?

答案:外部比较器,多态,扩展性好

TreeSet实现类的使用

【1】存入Integer类型数据:(底层利用的是内部比较器)

1.package com.msb.test10;
2.
3.import java.util.TreeSet;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Test01 {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个TreeSet:
12.        TreeSet<Integer> ts = new TreeSet<>();
13.        ts.add(12);
14.        ts.add(3);
15.        ts.add(7);
16.        ts.add(9);
17.        ts.add(3);
18.        ts.add(16);
19.        System.out.println(ts.size());
20.        System.out.println(ts);
21.
22.    }
23.}

特点:唯一,无序(没有按照输入顺序进行输出), 有序(按照升序进行遍历)

【2】原理:底层:二叉树(数据结构中的一个逻辑结构)

【3】放入String类型数据:(底层实现类内部比较器)

1.package com.msb.test10;
2.
3.import java.util.TreeSet;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Test02 {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个TreeSet:
12.        TreeSet<String> ts = new TreeSet<>();
13.        ts.add("elili");
14.        ts.add("blili");
15.        ts.add("alili");
16.        ts.add("elili");
17.        ts.add("clili");
18.        ts.add("flili");
19.        ts.add("glili");
20.        System.out.println(ts.size());
21.        System.out.println(ts);
22.    }
23.}

【4】想放入自定义的Student类型的数据:

(1)利用内部比较器:

1.package com.msb.test10;
2.
3./**
4. * @author : msb-zhaoss
5. */
6.public class Student implements Comparable<Student> {
7.    private int age;
8.    private String name;
9.
10.    public int getAge() {
11.        return age;
12.    }
13.
14.    public void setAge(int age) {
15.        this.age = age;
16.    }
17.
18.    public String getName() {
19.        return name;
20.    }
21.
22.    public void setName(String name) {
23.        this.name = name;
24.    }
25.
26.    public Student(int age, String name) {
27.        this.age = age;
28.        this.name = name;
29.    }
30.
31.    @Override
32.    public String toString() {
33.        return "Student{" +
34.                "age=" + age +
35.                ", name='" + name + '\'' +
36.                '}';
37.    }
38.
39.
40.    @Override
41.    public int compareTo(Student o) {
42.        return this.getAge()-o.getAge();
43.    }
44.}
1.package com.msb.test10;
2.
3.import java.util.TreeSet;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Test03 {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //创建一个TreeSet:
12.        TreeSet<Student> ts = new TreeSet<>();
13.        ts.add(new Student(10,"elili"));
14.        ts.add(new Student(8,"blili"));
15.        ts.add(new Student(4,"alili"));
16.        ts.add(new Student(9,"elili"));
17.        ts.add(new Student(10,"flili"));
18.        ts.add(new Student(1,"dlili"));
19.        System.out.println(ts.size());
20.        System.out.println(ts);
21.    }
22.}

(2)通过外部比较器:

1.package com.msb.test10;
2.
3.import java.util.Comparator;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Student  {
9.    private int age;
10.    private String name;
11.
12.    public int getAge() {
13.        return age;
14.    }
15.
16.    public void setAge(int age) {
17.        this.age = age;
18.    }
19.
20.    public String getName() {
21.        return name;
22.    }
23.
24.    public void setName(String name) {
25.        this.name = name;
26.    }
27.
28.    public Student(int age, String name) {
29.        this.age = age;
30.        this.name = name;
31.    }
32.
33.    @Override
34.    public String toString() {
35.        return "Student{" +
36.                "age=" + age +
37.                ", name='" + name + '\'' +
38.                '}';
39.    }
40.
41.
42.
43.}
44.
45.class BiJiao implements Comparator<Student>{
46.    @Override
47.    public int compare(Student o1, Student o2) {
48.        return o1.getName().compareTo(o2.getName());
49.    }
50.}
1.package com.msb.test10;
2.
3.import java.util.Comparator;
4.import java.util.TreeSet;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test03 {
10.    //这是main方法,程序的入口
11.    public static void main(String[] args) {
12.        //创建一个TreeSet:
13.        //利用外部比较器,必须自己制定:
14.        Comparator<Student> com = new BiJiao();
15.        TreeSet<Student> ts = new TreeSet<>(com);//一旦指定外部比较器,那么就会按照外部比较器来比较
16.        ts.add(new Student(10,"elili"));
17.        ts.add(new Student(8,"blili"));
18.        ts.add(new Student(4,"alili"));
19.        ts.add(new Student(9,"elili"));
20.        ts.add(new Student(10,"flili"));
21.        ts.add(new Student(1,"dlili"));
22.        System.out.println(ts.size());
23.        System.out.println(ts);
24.    }
25.}

实际开发中利用外部比较器多,因为扩展性好(多态)

换一种写法:

1.package com.msb.test10;
2.
3.import java.util.Comparator;
4.import java.util.TreeSet;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test03 {
10.    //这是main方法,程序的入口
11.    public static void main(String[] args) {
12.        //创建一个TreeSet:
13.        //利用外部比较器,必须自己制定:
14.        /*Comparator<Student> com = new Comparator<Student>() {
15.            @Override
16.            public int compare(Student o1, Student o2) {
17.                return o1.getName().compareTo(o2.getName());
18.            }
19.        };*/
20.        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
21.            @Override
22.            public int compare(Student o1, Student o2) {
23.                return o1.getName().compareTo(o2.getName());
24.            }
25.        });//一旦指定外部比较器,那么就会按照外部比较器来比较
26.        ts.add(new Student(10,"elili"));
27.        ts.add(new Student(8,"blili"));
28.        ts.add(new Student(4,"alili"));
29.        ts.add(new Student(9,"elili"));
30.        ts.add(new Student(10,"flili"));
31.        ts.add(new Student(1,"dlili"));
32.        System.out.println(ts.size());
33.        System.out.println(ts);
34.    }
35.}

【5】TreeSet底层的二叉树的遍历是按照升序的结果出现的,这个升序是靠中序遍历得到的:

Collection部分整体结构图

Map接口

常用方法

1.package com.msb.test11;
2.
3.import java.util.Collection;
4.import java.util.HashMap;
5.import java.util.Map;
6.import java.util.Set;
7.
8./**
9. * @author : msb-zhaoss
10. */
11.public class Test01 {
12.    //这是main方法,程序的入口
13.    public static void main(String[] args) {
14.        /*
15.        增加:put(K key, V value)
16.        删除:clear() remove(Object key)
17.        修改:
18.        查看:entrySet() get(Object key) keySet() size() values()
19.        判断:containsKey(Object key) containsValue(Object value)
20.            equals(Object o) isEmpty()
21.         */
22.        //创建一个Map集合:无序,唯一
23.        Map<String,Integer> map = new HashMap<>();
24.        System.out.println(map.put("lili", 10101010));
25.        map.put("nana",12345234);
26.        map.put("feifei",34563465);
27.        System.out.println(map.put("lili", 34565677));
28.        map.put("mingming",12323);
29.        /*map.clear();清空*/
30.        /*map.remove("feifei");移除*/
31.        System.out.println(map.size());
32.        System.out.println(map);
33.
34.        System.out.println(map.containsKey("lili"));
35.        System.out.println(map.containsValue(12323));
36.        Map<String,Integer> map2 = new HashMap<>();
37.        System.out.println(map2.put("lili", 10101010));
38.        map2.put("nana",12345234);
39.        map2.put("feifei",34563465);
40.        System.out.println(map2.put("lili", 34565677));
41.        map2.put("mingming2",12323);
42.        System.out.println(map==map2);
43.        System.out.println(map.equals(map2));//equals进行了重写,比较的是集合中的值是否一致
44.
45.        System.out.println("判断是否为空:"+map.isEmpty());
46.
47.        System.out.println(map.get("nana"));
48.        System.out.println("-----------------------------------");
49.        //keySet()对集合中的key进行遍历查看:
50.        Set<String> set = map.keySet();
51.        for(String s:set){
52.            System.out.println(s);
53.        }
54.        System.out.println("-----------------------------------");
55.        //values()对集合中的value进行遍历查看:
56.        Collection<Integer> values = map.values();
57.        for(Integer i:values){
58.            System.out.println(i);
59.        }
60.        System.out.println("-----------------------------------");
61.        //get(Object key) keySet()
62.        Set<String> set2 = map.keySet();
63.        for(String s:set2){
64.            System.out.println(map.get(s));
65.        }
66.        System.out.println("-----------------------------------");
67.        //entrySet()
68.        Set<Map.Entry<String, Integer>> entries = map.entrySet();
69.        for(Map.Entry<String, Integer> e:entries){
70.            System.out.println(e.getKey()+"----"+e.getValue());
71.        }
72.    }
73.}
TreeMap

【1】key的类型为String类型:

1.package com.msb.test11;
2.
3.import java.util.Map;
4.import java.util.TreeMap;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test02 {
10.    //这是main方法,程序的入口
11.    public static void main(String[] args) {
12.        Map<String,Integer> map = new TreeMap<>();
13.        map.put("blili",1234);
14.        map.put("alili",2345);
15.        map.put("blili",5467);
16.        map.put("clili",5678);
17.        map.put("dlili",2345);
18.        System.out.println(map.size());
19.        System.out.println(map);
20.    }
21.}
22.

【2】key的类型是一个自定义的引用数据类型:

(1)内部比较器:

1.package com.msb.test11;
2.
3.import java.util.Map;
4.import java.util.TreeMap;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test03 {
10.    //这是main方法,程序的入口
11.    public static void main(String[] args) {
12.        Map<Student,Integer> map = new TreeMap<>();
13.        map.put(new Student(19,"blili",170.5),1001);
14.        map.put(new Student(18,"blili",150.5),1003);
15.        map.put(new Student(19,"alili",180.5),1023);
16.        map.put(new Student(17,"clili",140.5),1671);
17.        map.put(new Student(10,"dlili",160.5),1891);
18.        System.out.println(map);
19.        System.out.println(map.size());
20.    }
21.}
1.package com.msb.test11;
2.
3./**
4. * @author : msb-zhaoss
5. */
6.public class Student implements Comparable<Student>{
7.    private int age;
8.    private String name;
9.    private double height;
10.
11.    public int getAge() {
12.        return age;
13.    }
14.
15.    public void setAge(int age) {
16.        this.age = age;
17.    }
18.
19.    public String getName() {
20.        return name;
21.    }
22.
23.    public void setName(String name) {
24.        this.name = name;
25.    }
26.
27.    public double getHeight() {
28.        return height;
29.    }
30.
31.    public void setHeight(double height) {
32.        this.height = height;
33.    }
34.
35.    public Student(int age, String name, double height) {
36.        this.age = age;
37.        this.name = name;
38.        this.height = height;
39.    }
40.
41.    @Override
42.    public String toString() {
43.        return "Student{" +
44.                "age=" + age +
45.                ", name='" + name + '\'' +
46.                ", height=" + height +
47.                '}';
48.    }
49.
50.    @Override
51.    public int compareTo(Student o) {
52.       /* return this.getAge()-o.getAge();*/
53.        return this.getName().compareTo(o.getName());
54.    }
55.}

(2)外部比较器:

1.package com.msb.test11;
2.
3.import java.util.Comparator;
4.import java.util.Map;
5.import java.util.TreeMap;
6.
7./**
8. * @author : msb-zhaoss
9. */
10.public class Test03 {
11.    //这是main方法,程序的入口
12.    public static void main(String[] args) {
13.        Map<Student,Integer> map = new TreeMap<>(new Comparator<Student>() {
14.            @Override
15.            public int compare(Student o1, Student o2) {
16.                return ((Double)(o1.getHeight())).compareTo((Double)(o2.getHeight()));
17.            }
18.        });
19.        map.put(new Student(19,"blili",170.5),1001);
20.        map.put(new Student(18,"blili",150.5),1003);
21.        map.put(new Student(19,"alili",180.5),1023);
22.        map.put(new Student(17,"clili",140.5),1671);
23.        map.put(new Student(10,"dlili",160.5),1891);
24.        System.out.println(map);
25.        System.out.println(map.size());
26.    }
27.}

Map部分整体结构图

源码部分

HashMap

代码展示特性

1.package com.msb.test03;
2.
3.import java.util.HashMap;
4.
5./**
6. * @author : msb-zhaoss
7. */
8.public class Test {
9.    //这是main方法,程序的入口
10.    public static void main(String[] args) {
11.        //JDK1.7以后支持后面的<>中内容可以不写
12.        HashMap<Integer,String> hm = new HashMap<>();
13.        System.out.println(hm.put(12,"丽丽"));
14.        System.out.println(hm.put(7,"菲菲"));
15.        System.out.println(hm.put(19,"露露"));
16.        System.out.println(hm.put(12,"明明"));
17.        System.out.println(hm.put(6,"莹莹"));
18.        System.out.println("集合的长度:"+hm.size());
19.        System.out.println("集合中内容查看:"+hm);
20.
21.    }
22.}
23.

结果展示:

先演示原理

先演示原理图,再看源码,直接看的话,有的人接不上就蒙了:

相当于先看原理,然后从源码中验证这个原理是否正确:把图搞懂了,就是事倍功半的效果

原理如下:(JDK1.7)

源码(JDK1.7版本)
1.public class HashMap<K,V>
2.    extends AbstractMap<K,V> //【1】继承的AbstractMap中,已经实现了Map接口
3.        //【2】又实现了这个接口,多余,但是设计者觉得没有必要删除,就这么地了
4.    implements Map<K,V>, Cloneable, Serializable{
5.                
6.                
7.        //【3】后续会用到的重要属性:先粘贴过来:
8.    static final int DEFAULT_INITIAL_CAPACITY = 16;//哈希表主数组的默认长度
9.        //定义了一个float类型的变量,以后作为:默认的装填因子,加载因子是表示Hsah表中元素的填满的程度
10.        //太大容易引起哈西冲突,太小容易浪费  0.75是经过大量运算后得到的最好值
11.        //这个值其实可以自己改,但是不建议改,因为这个0.75是大量运算得到的
12.        static final float DEFAULT_LOAD_FACTOR = 0.75f;
13.        transient Entry<K,V>[] table;//主数组,每个元素为Entry类型
14.        transient int size;
15.        int threshold;//数组扩容的界限值,门槛值   16*0.75=12 
16.        final float loadFactor;//用来接收装填因子的变量
17.        
18.        //【4】查看构造器:内部相当于:this(16,0.75f);调用了当前类中的带参构造器
19.        public HashMap() {
20.        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
21.    }
22.        //【5】本类中带参数构造器:--》作用给一些数值进行初始化的!
23.        public HashMap(int initialCapacity, float loadFactor) {
24.
25.        //【6】给capacity赋值,capacity的值一定是 大于你传进来的initialCapacity 的 最小的 2的倍数
26.        int capacity = 1;
27.        while (capacity < initialCapacity)
28.            capacity <<= 1;
29.
30.                //【7】给loadFactor赋值,将装填因子0.75赋值给loadFactor
31.        this.loadFactor = loadFactor;
32.                //【8】数组扩容的界限值,门槛值
33.        threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
34.                
35.                //【9】给table数组赋值,初始化数组长度为16
36.        table = new Entry[capacity];
37.                   
38.    }
39.        //【10】调用put方法:
40.        public V put(K key, V value) {
41.                //【11】对空值的判断
42.        if (key == null)
43.            return putForNullKey(value);
44.                //【12】调用hash方法,获取哈希码
45.        int hash = hash(key);
46.                //【14】得到key对应在数组中的位置
47.        int i = indexFor(hash, table.length);
48.                //【16】如果你放入的元素,在主数组那个位置上没有值,e==null  那么下面这个循环不走
49.                //当在同一个位置上放入元素的时候
50.        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
51.            Object k;
52.                        //哈希值一样  并且  equals相比一样   
53.                        //(k = e.key) == key  如果是一个对象就不用比较equals了
54.            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
55.                V oldValue = e.value;
56.                e.value = value;
57.                e.recordAccess(this);
58.                return oldValue;
59.            }
60.        }
61.
62.        modCount++;
63.                //【17】走addEntry添加这个节点的方法:
64.        addEntry(hash, key, value, i);
65.        return null;
66.    }
67.        
68.        //【13】hash方法返回这个key对应的哈希值,内部进行二次散列,为了尽量保证不同的key得到不同的哈希码!
69.        final int hash(Object k) {
70.        int h = 0;
71.        if (useAltHashing) {
72.            if (k instanceof String) {
73.                return sun.misc.Hashing.stringHash32((String) k);
74.            }
75.            h = hashSeed;
76.        }
77.                //k.hashCode()函数调用的是key键值类型自带的哈希函数,
78.                //由于不同的对象其hashCode()有可能相同,所以需对hashCode()再次哈希,以降低相同率。
79.        h ^= k.hashCode();
80.
81.        // This function ensures that hashCodes that differ only by
82.        // constant multiples at each bit position have a bounded
83.        // number of collisions (approximately 8 at default load factor).
84.                /*
85.                接下来的一串与运算和异或运算,称之为“扰动函数”,
86.                扰动的核心思想在于使计算出来的值在保留原有相关特性的基础上,
87.                增加其值的不确定性,从而降低冲突的概率。
88.                不同的版本实现的方式不一样,但其根本思想是一致的。
89.                往右移动的目的,就是为了将h的高位利用起来,减少哈西冲突
90.                */
91.        h ^= (h >>> 20) ^ (h >>> 12);
92.        return h ^ (h >>> 7) ^ (h >>> 4);
93.    }
94.        //【15】返回int类型数组的坐标
95.        static int indexFor(int h, int length) {
96.                //其实这个算法就是取模运算:h%length,取模效率不如位运算
97.        return h & (length-1);
98.    }
99.        //【18】调用addEntry
100.        void addEntry(int hash, K key, V value, int bucketIndex) {
101.                //【25】size的大小  大于 16*0.75=12的时候,比如你放入的是第13个,这第13个你打算放在没有元素的位置上的时候
102.        if ((size >= threshold) && (null != table[bucketIndex])) {
103.                        //【26】主数组扩容为2倍
104.            resize(2 * table.length);
105.                        //【30】重新调整当前元素的hash码
106.            hash = (null != key) ? hash(key) : 0;
107.                        //【31】重新计算元素位置
108.            bucketIndex = indexFor(hash, table.length);
109.        }
110.                //【19】将hash,key,value,bucketIndex位置  封装为一个Entry对象:
111.        createEntry(hash, key, value, bucketIndex);
112.    }
113.        //【20】
114.        void createEntry(int hash, K key, V value, int bucketIndex) {
115.                //【21】获取bucketIndex位置上的元素给e
116.        Entry<K,V> e = table[bucketIndex];
117.                //【22】然后将hash, key, value封装为一个对象,然后将下一个元素的指向为e (链表的头插法)
118.                //【23】将新的Entry放在table[bucketIndex]的位置上
119.        table[bucketIndex] = new Entry<>(hash, key, value, e);
120.                //【24】集合中加入一个元素 size+1
121.        size++;
122.    }
123.    //【27】
124.        void resize(int newCapacity) {
125.        Entry[] oldTable = table;
126.        int oldCapacity = oldTable.length;
127.        if (oldCapacity == MAXIMUM_CAPACITY) {
128.            threshold = Integer.MAX_VALUE;
129.            return;
130.        }
131.                //【28】创建长度为newCapacity的数组
132.        Entry[] newTable = new Entry[newCapacity];
133.        boolean oldAltHashing = useAltHashing;
134.        useAltHashing |= sun.misc.VM.isBooted() &&
135.                (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
136.        boolean rehash = oldAltHashing ^ useAltHashing;
137.                //【28.5】转让方法:将老数组中的东西都重新放入新数组中
138.        transfer(newTable, rehash);
139.                //【29】老数组替换为新数组
140.        table = newTable;
141.                //【29.5】重新计算
142.        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
143.    }
144.        //【28.6】
145.        void transfer(Entry[] newTable, boolean rehash) {
146.        int newCapacity = newTable.length;
147.        for (Entry<K,V> e : table) {
148.            while(null != e) {
149.                Entry<K,V> next = e.next;
150.                if (rehash) {
151.                    e.hash = null == e.key ? 0 : hash(e.key);
152.                }
153.                                //【28.7】将哈希值,和新的数组容量传进去,重新计算key在新数组中的位置
154.                int i = indexFor(e.hash, newCapacity);
155.                                //【28.8】头插法
156.                e.next = newTable[i];//获取链表上元素给e.next
157.                newTable[i] = e;//然后将e放在i位置 
158.                e = next;//e再指向下一个节点继续遍历
159.            }
160.        }
161.    }
162.
163.
164.
165.
166.
167.
168.}
细节讲解:主数组的长度为2的倍数

【1】主数组的长度为2的倍数,

因为这个length的长度,会影响 key的位置:

key的位置的计算:

实际上这个算法就是:  h%length   ,但是取模的话  效率太低,所以用位运算效率会很高。

原因·1:h%lenght和h&(length-1);

等效的前提就是  length必须是2的整数倍

原因2:如果不是2的整数倍,那么 哈西碰撞 哈西冲突的概率就高了很多

位运算 就  涉及  到  length是不是2的整数倍:

比如是2的整数倍:

并且这个得到的索引值,一定在 0-15之间(数组是16的时候):

当然如果你扩容后数组长度为 32,那么这个索引就在0-31之间

比如如果不是2的整数倍:

发现:如果不是2的整数倍,那么 哈西碰撞 哈西冲突的概率就高了很多

细节讲解:装填因子0.75的原因

如果装填因子是1, 那么数组满了再扩容,可以做到  最大的空间利用率 

但是这是一个理想状态,元素不可能完全的均匀分布,很可能就哈西碰撞产生链表了。产生链表的话 查询时间就长了。 

---》空间好,时间不好

那么有人说 ,把装填因子搞小一点,0.5,  如果是0.5的话,就浪费空间,但是可以做到 到0.5就扩容 ,然后哈西碰撞就少,

不产生链表的话,那么查询效率很高   

---》时间好,空间不好

所以在空间和时间中,取中间值,平衡这个因素 就取值为 0.75

HashSet底层原理
2.public class HashSet<E>{
3.    //重要属性:
4.    private transient HashMap<E,Object> map;
5.    private static final Object PRESENT = new Object();
6.    //构造器:
7.    public HashSet() {
8.        map = new HashMap<>();//HashSet底层就是利用HashMap来完成的
9.    }
10.        
11.    public boolean add(E e) {
12.        return map.put(e, PRESENT)==null;
13.    }      
14.}
TreeMap

【1】原理大致介绍:

【2】源码: 

1.public class TreeMap<K,V>{
2.        //重要属性:
3.        //外部比较器:
4.        private final Comparator<? super K> comparator;
5.        //树的根节点:
6.        private transient Entry<K,V> root = null;
7.        //集合中元素的数量:
8.        private transient int size = 0;
9.        //空构造器:
10.        public TreeMap() {
11.        comparator = null;//如果使用空构造器,那么底层就不使用外部比较器
12.    }
13.        //有参构造器:
14.        public TreeMap(Comparator<? super K> comparator) {
15.        this.comparator = comparator;//如果使用有参构造器,那么就相当于指定了外部比较器
16.    }
17.        
18.        public V put(K key, V value) {//k,V的类型在创建对象的时候确定了
19.        //如果放入的是第一对元素,那么t的值为null
20.        Entry<K,V> t = root;//在放入第二个节点的时候,root已经是根节点了
21.                //如果放入的是第一个元素的话,走入这个if中:
22.        if (t == null) {
23.                        //自己跟自己比
24.            compare(key, key); // type (and possibly null) check
25.                        //根节点确定为root
26.            root = new Entry<>(key, value, null);
27.                        //size值变为1
28.            size = 1;
29.            modCount++;
30.            return null;
31.        }
32.                
33.        int cmp;
34.        Entry<K,V> parent;
35.        // split comparator and comparable paths
36.                //将外部比较器赋给cpr:
37.        Comparator<? super K> cpr = comparator;
38.                //cpr不等于null,意味着你刚才创建对象的时候调用了有参构造器,指定了外部比较器
39.        if (cpr != null) {
40.            do {
41.                parent = t;
42.                cmp = cpr.compare(key, t.key);//将元素的key值做比较
43.                                //cmp返回的值就是int类型的数据:
44.                                //要是这个值《0 =0  》0
45.                if (cmp < 0)
46.                    t = t.left;
47.                else if (cmp > 0)
48.                    t = t.right;
49.                else//cpm==0
50.                                //如果key的值一样,那么新的value替换老的value  但是key不变 因为key是唯一的
51.                    return t.setValue(value);
52.            } while (t != null);
53.        }
54.                //cpr等于null,意味着你刚才创建对象的时候调用了空构造器,没有指定外部比较器,使用内部比较器
55.        else {
56.            if (key == null)
57.                throw new NullPointerException();
58.            Comparable<? super K> k = (Comparable<? super K>) key;
59.            do {
60.                parent = t;
61.                cmp = k.compareTo(t.key);//将元素的key值做比较
62.                if (cmp < 0)
63.                    t = t.left;
64.                else if (cmp > 0)
65.                    t = t.right;
66.                else
67.                    return t.setValue(value);
68.            } while (t != null);
69.        }
70.        Entry<K,V> e = new Entry<>(key, value, parent);
71.        if (cmp < 0)
72.            parent.left = e;
73.        else
74.            parent.right = e;
75.        fixAfterInsertion(e);
76.        size++;//size加1 操作
77.        modCount++;
78.        return null;
79.    }
80.        
81.        
82.}
83.
84.
85.
86. static final class Entry<K,V> implements Map.Entry<K,V> {
87.        K key;
88.        V value;
89.        Entry<K,V> left = null;
90.        Entry<K,V> right = null;
91.        Entry<K,V> parent;
92.        boolean color = BLACK;
93. }
TreeSet源码
1.public class TreeSet<E> extends AbstractSet<E>
2.    implements NavigableSet<E>, Cloneable, java.io.Serializable{
3.                //重要属性:
4.                private transient NavigableMap<E,Object> m;
5.                private static final Object PRESENT = new Object();
6.                
7.                //在调用空构造器的时候,底层创建了一个TreeMap
8.                public TreeSet() {
9.                        this(new TreeMap<E,Object>());
10.                }
11.                
12.                TreeSet(NavigableMap<E,Object> m) {
13.                        this.m = m;
14.                }
15.                
16.                public boolean add(E e) {
17.        return m.put(e, PRESENT)==null;
18.    }
19.                
20.                
21.        }

Collections工具类

1.package com.msb.test12;
2.
3.import java.util.ArrayList;
4.import java.util.Collections;
5.
6./**
7. * @author : msb-zhaoss
8. */
9.public class Test01 {
10.    //这是main方法,程序的入口
11.    public static void main(String[] args) {
12.        //Collections不支持创建对象,因为构造器私有化了
13.        /*Collections cols = new Collections();*/
14.        //里面的属性和方法都是被static修饰,我们可以直接用类名.去调用即可:
15.        //常用方法:
16.        //addAll:
17.        ArrayList<String> list = new ArrayList<>();
18.        list.add("cc");
19.        list.add("bb");
20.        list.add("aa");
21.        Collections.addAll(list,"ee","dd","ff");
22.        Collections.addAll(list,new String[]{"gg","oo","pp"});
23.        System.out.println(list);
24.        //binarySearch必须在有序的集合中查找:--》排序:
25.        Collections.sort(list);//sort提供的是升序排列
26.        System.out.println(list);
27.        //binarySearch
28.        System.out.println(Collections.binarySearch(list, "cc"));
29.
30.        //copy:替换方法
31.        ArrayList<String> list2 = new ArrayList<>();
32.        Collections.addAll(list2,"tt","ss");
33.        Collections.copy(list,list2);//将list2的内容替换到list上去
34.        System.out.println(list);
35.        System.out.println(list2);
36.
37.        //fill 填充
38.        Collections.fill(list2,"yyy");
39.        System.out.println(list2);
40.
41.
42.
43.    }
44.}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/220462.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 自动化之批量处理文件(一)

批量新建目录、文档Pro版本 文章目录 批量新建目录、文档Pro版本前言一、做成什么样子二、基本思路1.引入库2.基本架构 三、用户输入模块四、数据处理模块1.excel表格数据获取2.批量数据的生成 总结 前言 我来写一个不一样的批量新建吧。在工作中&#xff0c;有些同学应该会遇…

css 使用flex 完成瀑布流布局

瀑布流布局在商城类、文章类 app、网页中都是常用的&#xff0c;使用这样的形式&#xff0c;能过让整个页面更加的活波&#xff0c;也能让图片根据实际的大小来显示&#xff0c;更好的展示图片内容。那么代码如何实现呢 实现的效果 代码 <template><view class"…

登录/验证码/注册

登录 pom文件 <!--hutool工具类--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.9</version></dependency><!--jwt--><dependency><groupId>io.jsonw…

【解决】Windows 11检测提示电脑不支持 TPM 2.0(注意从DTPM改为PTT)

win11升级&#xff0c;tpm不兼容 写在最前面1. 打开电脑健康状况检查2. 开启tpm3. 微星主板AMD平台开启TPM2.0解决电脑健康状况检查显示可以安装win11&#xff0c;但是系统更新里显示无法更新 写在最前面 我想在台式电脑上用win11的专注模式&#xff0c;但win10不支持 1. 打…

基于自动化脚本批量上传依赖到nexus内网私服

前言 因为某些原因某些企业希望私服是不能连接外网的&#xff0c;所以需要某些开源依赖需要我们手动导入到nexus中&#xff0c;尽管nexus为我们提供了web页面。但是一个个手动导入显然是一个庞大的工程。 对此我们就不妨基于脚本的方式实现这一过程。 预期效果 笔者本地仓库…

在Node.js中MongoDB插入数据的方法

本文主要介绍在Node.js中MongoDB插入数据的方法。 目录 Node.js中MongoDB插入数据使用MongoDB原生驱动插入数据使用Mongoose插入数据 Node.js中MongoDB插入数据 在Node.js中&#xff0c;可以使用MongoDB原生驱动或Mongoose库来连接和操作MongoDB数据库。 以下是在Node.js中使用…

电子印章法律风险点及安全防范措施

公章是公司处理内外部事务的印鉴&#xff0c;公司对外的正式信函、文件、报告使用公章&#xff0c;盖了公章的文件具有法律效力。公章由公司的法定代表人执掌&#xff0c;法定代表人如果把法定代表人章与公章一同使用就代表公司行为。 随着社会数字化转型&#xff0c;电子印章及…

持续集成交付CICD:CentOS 7 安装SaltStack

目录 一、理论 1.SaltStack 二、实验 1.主机一安装master 2.主机二安装第一台minion 3.主机三安装第二台minion 4.测试SaltStack 一、理论 1.SaltStack &#xff08;1&#xff09;概念 SaltStack是基于python开发的一套C/S自动化运维工具&#xff0c;通信采用了zerom…

【UML】组件图中的供需接口与面向对象中的接口

UML&#xff08;统一建模语言&#xff09;组件图中的“供接口”&#xff08;Provided Interface&#xff09;和“需接口”&#xff08;Required Interface&#xff09;与面向对象编程中的接口概念有关联&#xff0c;但它们在应用上有所区别。 下面解释两者的关系&#xff1a; …

2023下半年软考复盘反思

工作十几年了&#xff0c;一直想考一个高级职称、但是疫情三年也没心思考&#xff0c;不想出去折腾。疫情过去&#xff0c;今年下半年想考一个&#xff0c;由于工作忙&#xff0c;准备了30天&#xff0c;成绩已经出了&#xff0c;先说结果&#xff1a;未通过。现在对这个过程反…

ElementPlus中的分页逻辑与实现

ElementPlus中的分页逻辑与实现 分页是web开发中必不可少的组件&#xff0c;element团队提供了简洁美观的分页组件&#xff0c;配合table数据可以实现即插即用的分页效果。分页的实现可以分成两种&#xff0c;一是前端分页&#xff0c;二是后端分页。这两种分页分别适用于不同…

three.js(二)

three.js&#xff08;二&#xff09; 参考前言正文简单开始(不使用任何框架)补充 粗略带过(使用Vue框架)细致讲解(比如我使用react框架)App.jsx 的进阶版 项目打包补充打包遇到的问题:原因:解决办法: 参考 https://threejs.org/docs/ 前言 上一集中,我们用到了three.js的一个…

AUTOSAR_RS_LogAndTrace中文翻译(待更)

4功能概述 5.功能要求 5.2.1.1通用型 1.日志记录应支持初始化和注册 2. 日志功能应该使应用程序提供日志信息 3. 日志功能应能和追踪应用程序之间通信&#xff0c; 4. 日志应支持对日志信息进行分组&#xff0c;使用案例&#xff1a;关联过滤所有属于一起的日志信息 5. 日志记…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十四:系统设置模块相关功能实现

一、本章内容 本章使用已实现的公共组件实现系统管理中的系统设置模块相关功能,包括菜单管理、角色管理、日志管理、用户管理、系统配置、数据字典等。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 3.1 B站视频地址:

scrapy post请求——百度翻译(十四)

scrapy处理 post 请求 爬取百度翻译界面 目录 1.创建项目及爬虫文件 2.发送post请求 1.创建项目及爬虫文件 scrapy startproject scrapy_104 scrapy genspider translate fanyi.baidu.com 2.发送请求 post请求需要传递参数&#xff0c;所以就不能用start_urls和parse函数了&…

代码随想录刷题题Day12

刷题的第十二天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day12 任务 ● 层序遍历 10 ● 226.翻转二叉树 ● 101.对称二叉树 2 1 层序遍历 一口气做十题 102.二叉树的层序遍历 107.二叉树的…

数字化管理系统:引领企业智能化时代

随着数字化和智能化的风潮席卷而来&#xff0c;企业数字化管理系统成为提升竞争力、提高效率的不可或缺的工具。在服装管理系统、仓储管理系统等方面应用的RFID技术和数字大屏更是为企业带来了前所未有的便利和优势。 数字化管理系统的重要性&#xff1a; 数字化管理系统是企…

oracle数据恢复—Oracle报错“system01.dbf需要更多的恢复来保持一致性”的数据恢复案例

oracle数据库恢复环境&故障&#xff1a; 一台Windows server操作系统的服务器上部署Oracle数据库。 服务器意外断电导致oracle数据库报错&#xff0c;报错信息&#xff1a;“system01.dbf需要更多的恢复来保持一致性”。由于该oracle数据库并没有备份&#xff0c;仅有一些断…

算法通关村第十三关—数字与数学高频问题(白银)

数字与数学高频问题 一、数组实现加法专题 1.1 数组实现整数加法 先看一个用数组实现逐个加一的问题。LeetCode66.具体要求是由整数组成的非空数组所表示的非负整数&#xff0c;在其基础上加一。这里最高位数字存放在数组的首位&#xff0c;数组中每个元素只存储单个数字。并且…

数据库传奇:MySQL创世之父的两千金My、Maria

《数据库传奇&#xff1a;MySQL创世之父的两千金My、Maria》 一、前言 MySQL是一款备受欢迎的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;最初由瑞典公司MySQL AB开发&#xff0c;目前隶属于Oracle Corporation。在DB-Engines的排名中&#xff0c;MySQL稳…