java求职学习day11

1 集合的概述(重点)

1.1 集合的由来

(1)当需要在java程序中记录单个数据内容时,则声明一个变量。

(2)当需要在java程序中记录多个类型相同的数据内容时,声明一个一维数组。

(3)当需要在java程序中记录多个类型不同的数据内容时,则创建一个对象。

(4)当需要在java程序中记录多个类型相同的对象数据时,创建一个对象数组。

(5)当需要在java程序中记录多个类型不同的对象数据时,则准备一个集合。

分析:

声明变量的本质,其实就是在内存中申请一个小格子,然后把数据是不是塞进去对不对?

但是如果的话呢?我们要在JAVA程序中记录多个类型相同的数据内容时。那这个时候一个小格子是不是就已经不满足我们的需求了,这个时候怎么办?(问题1)

是不是我们就得申请一段连续的存储单元?而这一段连续的存储单元里面我们实际上是不是就可以怎么办?把它是不是分成很多个小格子,每个小格子里面是不是都可以放一个?一个数据内容。对不对?我们把这样的称之为一维数组。对不对?但是一维数组有个缺陷呀,那就是什么来着?它要求数组中的每个元素,或者说所有元素是不是都必须是相同的数据类型?对不对?也就是说你要么都放整数,要么都放小数,要么都放字符串儿。没错吧好,

那如果说我希望存放的是多个类型不同的数据内容,注意类型不同。那这个时候怎么办呢?问题2)

那接下来问题又来了,那如果我需要好多个对象怎么办呢?(问题3)

哎,要记录好多个对象,我们有没有办法呢?那这个时候我们是不是就可以用到一个叫对象数组的概念,那什么叫对象数组啊?其实说白了,就是说我们一个student类型的对象是不是可以存放一个学号和一个姓名。可以吧,

那如果说我现在要想记录咱们班,比如说50个100个这样的学生信息怎么办?我是不是就可以声明一个?前面讲过的吧,声明一个student类型的数组,

student类型的数组什么意思?就是数组中的每个元素都是一个student类型的变量。对不对?那这样的数组,我们其实就称之为对象数组,也就是说这个数组中每个元素其实是不是都是一个student类型的对象啊?明白这意思吧,所以我们把它称之为对象数组。

但是数组的特点又出现了,对吧?什么特点?就是我们这里面无论放的是普通的数据内容还是放的是对象,我们都有一个要求,就是类型必须都要相同

但是我们现实生活中又有一种情况呀,就是说我可能是要存放多个对象,但这多个对象的类型。有不同。那怎么办?(问题4)

这个时候我们就用到集合的概念。明白了吧,也就是说集合,其实说白了还是一个容器只不过呢,它跟变量一维数组啊不一样。变量的特点是只能存放单个数据内容,数组的特点是能放多个,但要求类型相同而集合,这种容器啊,跟前面两种容器相比。它的最大优势在于我可以存放多个类型不同的对象。是不是意味着功能更强大了?明白了吧,这就是我们集合的一个概念,和它的一个由来。

1.2 集合的框架结构

(1)java中集合框架顶层框架是:java.util.Collection集合和java.util.Map集合。

Collection集合和Map集合之间的区别是什么?

其中Collection集合中存取元素的基本单位是:单个元素。

其中Map集合中存取元素的基本单位是:单对元素。

分析:

要学的集合框架如下图所示:(要记住)

2 Collection集合(重点)

2.1 基本概念

(1)java.util.Collection接口是List接口、Queue接口以及Set接口的父接口,因此该接口里定义的方法既可用于操作List集合,也可用于操作Queue集合和Set集合。

从语法层面,它是接口;从功能方面,它是一个集合

2.2 常用方法

那么我们说了collection集合呀,它是一个容器,那容器的话无非就是对元素进行增删改查呗。所以我们按照这样的流程给大家介绍它的常用方法

2.2.1 方法boolean add(E e)boolean addAll(Collection<? extends E> c)在代码当中的使用 (增加操作)

add用来添加单个元素的;addAll用来添加多个元素的,在代码中的应用如下:

接口本身是不能new对象的,但是接口类型的引用是不是可以指向它的实现类的对象?但是能指向list的对象吗?不能因为list依然是个接口,意味着依然不能new对象,所以是不是只能指向在下面,具体的实现类的对象?好,那问大家用ArrayList类可以吗?可以啊,那无非就是声明一个collection类型的引用指向ArrayList类型的对象可以吧,这是典型的接口类型的引用指向,实现类的对象形成多态嘛。是不是多态的第二种使用场合对吧?只要涉及到抽象类,接口类型的引用,是不是只能指向实现类的对象形成多态。

大家知道只要字符串拼接,它就会怎么办?自动调用to string方法。不解释了吧,我那问大家调的是哪儿的toString(),实际上我们最终调用的是ArrayList类中的toString()方法呗,多态嘛,编译阶段调父类,运行阶段调子类嘛。

为什么不用new也可以呀?对常量池的概念嘛,String类中的常量池的概念对不对?可以new也可以不new,不new的时候只创建一个对象,在常量池;new的时候创建俩对象,一个在常量池,一个在堆区。

就是你一定要看清楚到底是把c2中的元素一个一个放进去呢,还是把c2当做一个整体?放进去,这二者之间是有区别的。

小细节:在这段代码中,Integer.valueOf(2) 是 Java 中的一个方法调用,用于获取表示指定 int 值(在这个例子中是 2)的 Integer 实例 

 

 小细节:有两种重写toString方法在ideal中(不用较真,只是之前没用过第一种,一直用的第二种,在这里做一个总结)

第一种:

第二种: 

2.2.2 对boolean contains(Object o)和boolean containsAll(Collection<?> c)方法介绍和使用:

 我这里面之所以用object作为形参往这一站,其实的目的就是在于你给我什么样的对象都可以传。那布尔类型的返回值代表什么意思?对布尔类型的返回值无非就代表你到底是否包含,包含就是true,不包含就是force。object是万物皆对象。objects它仅仅是一个工具类

 补充上面三张图片的一个问题:(如何在Person类中实现equals方法的重写)

 

2.2.3 对方法boolean contains(Object o)/boolean containsAll(Collection<?>c)的使用:

2.2.4 对boolean retainAll(Collection<?>)的使用(Collection集合实现交集的计算?)这图片中的本质要理解

2.2.5 对boolean remove(Object o)/boolean removeAll(Collection<>)的使用(Collection集合实现元素的删除)

 2.2.6 对void clear()/int size()/boolean isEmpty()/boolean equals(Object o)的使用

深究:我们知道0==c1.size()和c1.isEmpty()这两个方法实现的结果是一样的,那他们俩的内部有什么区别呢?

刚刚说到我们说size方法,实际上跟isEmpty的话呢,就是有点儿重叠,为什么呢?因为如果个数为零,不就是空了吗?所以我想看一下这俩方法的庐山真面目怎么办呢?

 

 啊?就是哎,就是万物皆对象对象的意思嘛,对不对?好,那这里面为什么要用object作为这个方法的返回值类型?对,还是我们前面讲那句话,因为集合中的元素可能是多种多样的,对吧?是多种不同类型的对象。那我只有用object作为返回值,是不是才能满足万物皆对象的理念,才能让它能够实现所有?

元素的这个通用。对不对?或者说统一的处理

collection是list呃集合的一个父集合呀,那你想想你用list都能接你用collection接,肯定也没问题呀。

2.2.7对Object[] toArray()方法的使用(Collection集合和数组的转换方式)

小细节:就是我们在输入Arrays.asList(objects);代码之后,我们按ctrl+enter,之后自动弹出来的是

List<Object> objects1 = Arrays.asList(objects);其中<Object>先不解释;

我们为了方便可以讲这段代码修改为:

Collection objects1 = Arrays.asList(objects);

没有报错的原因:Collection是List集合的一个父集合呀,那你想想你用list都能接,你用collection接,肯定也没问题呀。

2.2.8 对Iterator<E>iterator()的使用(Collection集合实现迭代器的使用):

那么我们怎么使用呢?首先得要调用iterator一个方法获取迭代器对象。那获得迭代器对象之后,返回的是一个叫iterator的这么一个接口。

明确循环条件吗?明确。但不明确循环次数,所以用while循环更擅长

按照上面第二个绿色框中的写法太低级,在开发中一般不这样写,一般这样写,如下图所示:

3 Iterator接口(重点)

3.1 基本概念

(1)java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。

(2)java.util.Collection接口继承Iterator接口,因此所有实现Collection接口的实现类都可以使用该迭代器对象。

3.2 常用的方法

 案例题目:如何使用迭代器实现toString方法的打印效果。

题目的具体体现:

思考过程:

那要想把它打出来,跟用toString方法的一模一样,实际上无非就是把我们用迭代器取出来,这些元素是不是用逗号加空格以及中括号拼接一下就行了?对不对?而拼接字符串,我们得需要用到哪个类?前面讲过的吧stringbuilder 类。

我是不是可以创建一个StringBuilder类型对象,然后在它的基础上拼接sb1.append拼接?

首先,是不是得有个左半拉中括号儿,所以先来个左半拉中括号儿再说。然后紧接着是不是就可以迭代了while?对不对啊?while然后判断叫iterator.hasNext()。

问大家这么写有问题吗?有,而且有一个很大的问题,什么问题?

我们刚刚在分析这段代码的时候,我们说迭代器,你可以把它理解为什么呀?理解为一个箭头,一开始在这儿,然后next一次下一个,最后是不是已经指到这了?也就是说,上面这个循环的代码执行完之后,这个迭代器是不是已经跑到了集合的末尾跑空了?那你现在拿着这个迭代器再去next?是不是这个条件一定不成立啊?

我们是不是得需要重置迭代器?这个迭代器就可以接着用了,然后紧接着拼接呗sb1.append,然后我们叫iterator.next()把元素拼接起来。但是除了元素值之外,还得需要什么逗号加空格呀

但这样写的话还是有个问题啊。什么问题?就是我们的话呢,第一个元素有逗号空格,第二个元素有逗号,后面有逗号空格,最后一个元素是不没有逗号空格?对吧,那如果这样写的话,是不每个元素的后面都会有个逗号加空格的?是吧,所以这不太帅气,所以我们这里面应该怎么办?

所以我们这里面是不是要判断,我怎么知道我取出这个元素,是不是最后一个元素?怎么判断取一个元素指向下一个位置,取一个元素指向下一个位置,我怎么知道它是不是最后一个元素?

所以要想判断一个元素是不是最后一个元素,其实只需要判断这个元素的后边还有没有呗,就取完这个元素之后,如果它后面没有元素了,说明刚刚取出这个元素,是不是就是最后一个

代码展示:

3.2.1 对方法void remove()方法的使用:(Colllection集合迭代的过程中删除元素)

1用迭代器的remove方和用集合的remove方法分别试一下

一个线程通常不允许修改Collection,而另一个线程正在迭代它,通常,在这些情况下,迭代的结果是不确定的,如果检测到此行为,可能会出现此异常。

分析:

晚上睡不着了,你正在数一只羊,两只羊,三只羊,然后突然间来了电话了,对不对?然后呢?接完电话之后是不是你忘了刚数到几只羊了?对不对哎?一样的意思。所以这里面的错误就在于我迭代器明明正在怎么办?迭代。我正在一只羊两只羊的数,结果一回头羊没了。如果调这个方法,是不是相当于一回头,羊没了?那不就完了吗?节奏乱了,迭代性破坏了,不就出现异常了吗?

有同学说,那为什么用自己的remove方法没问题啊?这就好比你自己在数一只羊,两只羊,三只羊,你停下来了,你停下来写个句话。对吧,然后是不是你把三记住了,然后写了一句话,然后回来你就接着四只羊,五只羊往上接着数。明白这意思了吗?

所以这里面到底有没有问题实实际上是不是就在于  因为你是自己在迭代,你自己删除,当然你自己知道了嘛。但如果你在迭代过程中,别人背着你删,是不是?那你不知道,你不就乱了吗?这个时候是不是就会发生异常?对不对?

当然,如果不是迭代,你只要不是在迭代的过程中,你用集合的remove方法是不是就没有任何问题?所以以后到底有没有问题,会不会错,取决于什么,取决于你到底是否在迭代的过程中调集合的运用方法。对不对?如果你希望在迭代的过程中就要调用删除方法,那就用迭代器的,

不要用集合的,否则容易发生并发修改异常(重点结论)。明白这意思吧,所以这个错误大家一定要尽量避免。

4 for each循环(重点)  Collection集合中使用foreach结构

4.1 基本概念

java5推出了增强for循环语句,可以应用数组和集合的遍历。(是for循环的升级版)

是经典迭代的简化版。

4.2 语法格式

for(元素类型 变量名:数组/集合名称){

          循环体;

}

注:元素类型指的是:数组、集合中的元素类型

代码展示:

4.3 执行流程

不断的从数组/集合中取出一个元素赋值给变量名并执行循环体,直到取完所有元素为止。

分析:

跟我们以前讲的for循环不一样,以前讲的for循环是不还得需要一个变量来控制次数啊?对不对?但这里啊,不需要了,因为它会怎么办呢?它会自动的从数组或者集合中不断的去取一个元素。取完元素之后,就会赋值给这个变量。明白这意思吧,赋值给这个变量之后,你拿这个变量就可以执行循环体,在循环体中可以进行处理,然后直到把这个数组或者集合中的元素全部取完。自动循环结束。是不是更省心啊

什么是调试?

所谓的调试,其实说白了就是让代码是不一步一步的去执行,然后我们是不是可以更清晰的看到代码的执行流程。然后去分析我们在代码编写过程中的一些逻辑错误。

注意:for each循环,主要作用就是遍历,不能修改元素/集合中的元素

 我们呃总结一下上面提到的所有代码,那么Collection集合中的元素遍历方式是不是就有三种?一种是最开始的toString()不太灵活,但是代码也很简单,还有一种迭代器,灵活,但代码复杂。还有一种呢,就是我们这里面的for each代码简单而且灵活。(很关键)

5 List集合(重中之重)

5.1 基本概念

(1)java.util.List集合是Collection集合的子集合,该集合中允许有重复的元素并且有先后放入次序。

(2)该集合的主要实现类有:ArrayList类、LinkedList类、Stack类、Vector类。(而这个list的话呢因为它毕竟是一个接口对不对那接口是不能new对象的,所以要想让使用它还得依赖于具体的,实现类)

(3)其中ArrayList类的底层是采用动态数组进行数据管理的,支持下标访问,增删元素不方便。

分析: 

array 这个单词我们在前面讲了它是什么概念?数组的概念。那么ArrayList实际上就说白了这个集合的底层还是一个数组呗。但是呢,这个集合它的底层虽然也用的是数组,但是它跟我们前面自己定义的数组相比的话它还是有所不同,哪儿不同呢?就两个字:动态。

什么叫动态数组啊,实际上我们在前面给大家讲过留过一个作业也讲过那个作业实际上就是我们以前自己声明的数组的话一旦声明之后数组的长度是不是就固定,当我们往数组里面放入的元素超过数组的容量时我们是不是就得自己再去new一个更大的空间,然后把原始数组里面的数据内容拷贝到新数组中,其实这个过程就叫动态,明白了吧,也就是说ArrayList类跟我们以前的我们自个儿写的这个数组不一样的地方在于,它把自动扩容的这个功能它内部已经封装实现完毕了,我们在用的时候我们只需要拿着ArrayList类去用就行,然后至于它的这个内部如何扩容,实际上我们都可以不用操心都由它自动完成,明白了吧,好这是这里面的动态数组二字的概念。

比如说我们拿着这一组元素12,13,14,15往ArrayList类里面放的时候实际上是不是相当于,我是依次放入的。因为它毕竟还是数组,所以它的特点是不是就访问很方便,因为通过下标访问,但是它有一个缺点就是增删不方便,这个我们在前面讲数组的时候也提过,为啥呢?因为我如果要想把前面这个元素删掉我是不是得把后面的元素依次挪到前面去,那如果我想往前面这个位置插入元素我是不是就得把这些元素又得往后挪,对不对。所以它的特点就是访问方便但是增删是不方便的,明白这意思吧,好这是它的一个特点。

好那么接下来的话呢就是哎它的一个就是数组本身的特点但是它又不同于数组的呢就在于,动态二字就是动态调整容量的大小,那么前面我们给大家讲的时候我们说在讲作业的时候我们说我们自个儿写的那个数组调整的策略是增加为原来的1.5倍,那我们接下来带大家去看一看那么ArrayList这个类它的底层是不是也是扩容为原来的一点五倍呢?

5.1.1ArrayList的内部代码逻辑(动态数组是如何实现的)

下面这些内容就是ArrayList类中的扩容机制的原理(就是看一下ArrayList类中动态数组在内部是如何实现的)(有视频2025/1/6)

首先第一步是不是就是他先干嘛来着,他先构造了一下,构造而且我们在new ArrayList的对象的时候我并没有传任何参数,那应该调的是无参构造方法对不对, (操作:点红色的小箭头我们是不是就可以进入源码的内部)但是进来之后大家会发现这不是我们想要的,是一个ClassLoader就是类加载的一个源码分析,哎这个过程我们暂时先不看,我们讲反射的时候再看,所以这里面我们怎么办呢?退出来,退一步然后再进去相当于我们就跳过了一步,然后再进去进入到源码中,现在是不是就进入到ArrayList的无参构造方法里面了,(操作按蓝色的向上的箭头+再按红色的向上的小箭头)

那无参构造方法里面做了一个什么事呢?大家看一下这里面是不是就写了一个叫this.element data,很明显这应该是一个成员变量,然后呢后面又等于一个值这是全部字母都大写,不同单词之间下划线连接,实际上这就是一个常量,就是说拿着这个常量是不是来给这个成员变量来初始化,那这里面的elementdata,还有这后面这都什么意思啊,不知道可以往前翻在这儿有。

elementData这是干嘛的呀?诶说这是一个数组的缓存区而且是一个object类型的数组,那也就是说什么意思啊?在ArrayList这个类的底层实际上是不是声明了一个叫object类型的一维数组,来负责,将我们添加的所有元素保存起来,所以验证了一点它的底层确实是一个数组,

而我们刚刚拿着什么值给来给element data初始化DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

,那这实际上是不是就是一个,object类型的一维数组而且用大括号初始化,实际上是不是就是一个空数组啊,那也就是说一开始我拿着这个空数组是不是来给成员变量elementdata进行初始化,也就是说它实际上是不是依然是一个空数组,那也就是说我们在new ArrayList类的对象时我并没有立刻是不是去申请数组的内存空间,对不对实际上是不是只是一个空的数组,所以你看在这里面我们实际上是不是就是一个空数组。

这下面这张图片主要是想传达一个事情就是我们现在对象已经成功创建了,接下来我们就要开始调add方法了

好看一下原码,这里面的话有一个叫modcount++,对不对哎modcount++这个东西我们暂时用不上先不管它,它的值是零。好然后接下来大家要注意这里面的e是什么?是one。e的值为啥是one,因为我们这里面是不是传的实参就是one,所以这里面的话呢得到值是不是就是one,好接下来继续往下执行,好size的值是多少来着?零。那此时大家注意e是什么来着?e还是one。所以大家会发现在add方法的内部其实是不是又调了一个名字为add的方法,他负责要把这个one也就是e的值放到elementData这个数组中然后,size的话的值是不是零,就是元素的个数还是零。

现在我们就要继续的进入内部的add方法:

接下来此时我们方法中s的值其实就是刚刚那个size的值,size的值其实就是零,对吧。那既然是零的话那也就意味着,我们接下来继续往下走它的值是零,然后接下来说s的值是否等于element data.length,对不对,好意味着就是说这个长度就是s的值是否等于数组的长度s的值,我们刚说了是零啊这也标识了是零,而数组的长度其实是不是也是零,因为一开始是空数组嘛,零等于零成立吗?成立。好继续往下执行,执行这个时候是不是就elementData就是这个存放元素的这个一维数组是不是等于grow(),

调用了一个名字叫grow的方法,grow什么意思啊其实说白了就是开辟内存的呗,啊继续进入到grow方法的内部,

对不对好进来进来之后grow方法里面大家注意内部的话呢是变成size+1,size是零,那size+1不就是几啊?0+1是1呗,然后是不是又调了另外一个grow方法,相当于是把1又作为参数调了另外一个grow,其实就是上面这个grow。那也就是说这个minCapacity,是不是就是1,也就是最小容量是不是就是1,回到我们刚刚所说的这个位置是不是就是它的值是1,然后这个Array点copyof,

这什么意思啊?这明显就是要将原始数组中的数据内容拷贝到新的数组中,那新的数组是不是首先得要申请这个数组的内存空间呀,对不对?好所以这里面是不是又调了一个叫new capacity的方法实际上就是申请内存空间呗,好然后接下来走,到这儿我想知道它内部,当然我这里minCapacity的值是不是还是1,

对不对好minCapacity刚说了是1,对不对,好然后呢紧接着接下来我们说用oldCapacity等于elementData.length,就是那个数组的长度呗,那个数组的长度是零吧,你看这儿写的零所以这个oldCapacity的值其实就是零,然后紧接着呢说让这个新的内存空间的大小等于旧的内存空间的大小再加上旧的内存空间向右移一位,零加上零右移一位不还是零吗?那相当于是零加零还是零呗,所以new capacity其实最终的结果是不是还是零,

所以newCapacity是零,oldCapacity也是零,对吧。哎这里面有一个小细节你会发现我们先获取原始数组中的长度,然后紧接着我拿着原始数组的长度加上这个原始的值向右移一位啊,那右移一位二进制位实际上是不是相当于是除以2;左移是乘以2。右移是除以2不就相当于是0.5吗?让原始数字的长度再加上0.5备的,数组的长度那加起来是不是就扩容为原来的一点五倍,对不对啊这不又回归到我们前面所说的了吗?好所以扩容的原理是原始数组的1.5倍,好然后紧接着呢,当然现在newCapacity的值是零,oldCapecity的值也是零。所以接下来继续往下走newCapacity的值是0,减去minCapacity的值1(minCapacity是不是就是一参数传过来的嘛,是size+1的效果还记得吧),然后紧接着呢,我们让0-1那实际上是不是就是,小于等于零,成立。好继续走,我再做一个判断就是说element data是否等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA;这个是吗这当然是了我们一开始我们new的时候就拿这个初始化的呀,所以这个条件是成立的,对吧这是成立的,那既然成立那意味着接下来进入里面执行呗,math.max认识吗?这个讲过吧就是在数学处理类中找最大值的一个类呗,那找谁跟谁的最大值?找的是defaultCapacity跟minCapacity的最大值,minCapacity的值是1,defaultCapacity(这不就叫默认初始容量的值是十,代码的前面有定义)的值是多少?你看光标放上面是10,所以这里面相当于是在十跟一之间怎么办,找最大值,十跟一之间找最大值那不就是十吗?所以return的其实是不是就是10,最终我们申请的这个数组的长度实际上是不是就是一个长度为十的数组,扩容的原理刚说了是不是原始数组的一点五倍。

至此,ArrayList类的扩容原理已经解释完毕。 

(4)其中LinkedList类的底层采用双向链表进行数据管理,访问不方便,增删元素方便。

(5)可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定差别,ArrayList更适合于随机访问而LinkedList更适合于插入和删除;在性能要求不是特别苛刻是情形下可以忽略这个差别。

分析:

什么叫双向链表啊?

比如说还是要存放一组元素,10,20,30,40,50,如果是我们前面讲的ArrayList的话,实际上是不是就是声明一个一维数组,然后挨着放,是不是就行了?对不对?但是LinkedList的底层是一个双向链表,那双向链表怎么理解啊?大家看一下这里面怎么存放的?

我是不是给每个元素申请了一块独立内存空间?10,20,30,40,50对不对,有说那你下面的这个绿色的这个字体,这是什么呀?这个代表的是当前这一块内存空间的地址。找着这个10之后,我根据10里面记录地址我是不是能找着20?根据20里面记录地址,我是不是能找着30,根据30里面记录地址,我是不是能找着40,根据40里面记录地址,是不是能找着50。以此类推?明白了吗?诶,这实际上是不是相当于我从前向后可以找着所有元素。那么反过来。大家再看。我把0x10是不是放到了20的上面;我把0x20是不是放到了30的上面;我把0x30是不放到了40的上面?我将0x40是不放到50上面,那意味着怎么做啊?我只要找着50,根据前面记录地址,我是不是可以找到40,根据地址能找着30,根据地址找到20,根据地址找着10对吗?以此类推。好,现在知道什么叫双向了吗?所谓的双向就是说你从前向后能找着,从后向前也能找,这叫双向链表。

这里面的每个小格子,我们叫什么呢?我们的专业术语都把它称之为一个节点。明白了吧,中间的话呢,叫做节点的元素值。上面呢,代表的是前一个节点的地址,下面的,放的是后一个节点的地址。

为什么说访问不方便?因为它的内存空间不是连续的呀,不支持下标,所以我得找的时候从前往后一个一个找,或者从后往前一个一个找。所以是不是增删方便,因为大量的元素前面后边的元素不需要移动啊,我只要让这绳儿拐个弯儿,重新连一下就行了呗。对不对好?所以大家会发现LinkedList跟我们的ArrayList相比,实际上是不是就是一个?互补的关系。

5.1.2 LinkedList类内部逻辑(双向链表是如何实现的):

里面是不什么都没有啊,也就是说。构造了一个空链表,就是相当于我们这个双向链表是不是空的呀?啥也没有。但是这个链表里面大家注意LinkedList里面有两个有三个成员。一个叫size,那应该是记录元素个数的呗。还有一个呢,叫node类型的first,first什么意思啊?这儿也标记了一下,这个node什么东西?node其实就叫节点,其实就是大家看到的这里面的每一个格子,这就叫node。明白了吧,然后呢,说有一个node类型的first,它是用来干嘛的?记录第一个节点的地址,也就是说,有一个 first相当于是一个小箭头儿,这个箭头儿负责指向第一个第一个节点,当然一开始没有节点的话,不就是空吗?对不对?还有一个叫last ,也是node类型的node类型的,是不是应该就指向node类型的对象?也就是说这里面还有一个叫last的这么一个箭头,它负责指向最后一个。明白了吧,因为为啥要有这两个呀,因为有了这两个之后,通过first从前往后能遍历完,通过last我是不是从后往前也能遍历完?对不对?就是说我们双线链表,它们之间相互之间已经连接起来了,但是我第一个元素得有人记,第一个节点得有得有,得有人记录吧,最后一个节点是不是也得有个地儿记录啊?所以我是不是又准备了两个引用负责记录这两边儿两个节点的地址。

然后接下来我是不是调add就开始添加了,那咋添加的呀?进入到源码中。那此时那里面的one拿过来是不是就变成这里面的小e了?小e就是one我拿着小e是不是又调了一个叫LinkedLast?linked表示的是链接,last表示的是后面,就是往后边链的意思,所以现在知道什么叫有先后放入次序了吗?因为每次我都往后面放啊。对不对?然后依然是return true,就无论这个方法,最终结果是什么来着?哎,就是这个方法,我们默认是不是都返回的是一个true,就是目前没有找着失败的原因嘛

首先是不是又生成了一个node类型的引用,然后让它的值怎么办?等于last,然后紧接着怎么办?我这里面是不是又来了一个叫node类型的new node?等于new node。对吧,啥意思啊?实际上就是创建这么一个小格子,小节点明白了吧,l的值是什么?l值我们说现在还是null呗,然后呢,紧接着接下来e是就是那个one那个字符串儿,然后呢next也是null,那我们再进一下构造,看它里面做什么事儿进入。

进来之后发现这实际上就是一个内部类,作为一个节点类,这个类里面有3个值,就这意思,也就是说我要放入一个元素的时候,我是不是把这个元素得先构造成这么个节点再往上链,item=element是不是说白了就是传过来的字符串one,刚next传过来,是不是null啊?那就相当于新创建这个结点的next值,是不是就null,就相当于我又创建了一个结点?相当于我又创建一个节点,对吧?然后这个新结点里面的元素值,我给的是one。对不对?然后这个结点的next的话呢?没有值,所以我们这儿给的是一个null。对吧,这不就是这个过程吗?这里面的prve是哪儿来的?是拿l的值一开始,这个l都是空嘛,所以这里面说白了,放的还是null。

此时是不是相当于创建一个节点创建完了对不对?而且找了一个叫newNode,指向这个新节点。接下来我们让last=newNode,就是把new node的值给了last,也就是说last是不是指向了new node,一开始这些都没有它,实际上是空的,现在让last是不是相当于是拐个弯?last拐个弯是不是指向它了,为啥因为last是负责记录最后一个节点的地址的,那么现在是因为一开始这个链表里面是空的嘛?那现在我们创建了一个节点,那么这个last是不是应该指向了这个新创建的这个节点。因为每次我们说新节点都是链到最后面嘛。好继续,然后接下来我们继续往下走呗,然后再判断说如果l==null,当然是了,现在我们只创建了一个节点,空链表last也是null,l也是null。first也等于newNote,什么意思啊?就是说发现诶这个空链表啊,那就让这个first也过来指向它吧。相当于first跟last都指向它,因为此时链表中只有一个结点,那么是不是它相当于既是头结点也是尾结点?好,然后对不对继续往下走?此时我们就让size++元素个数是不是加了1,

至此,LinkedList的内部逻辑已经完成 

(6)其中Stack类的底层是采用动态数组进行数据管理,该类主要用于描述一种具有后进先出特征的数据结构,叫做栈(Last in fast out LIFO)。(注意:Stack是一个类,可以直接new对象)

分析1:那什么叫后进先出啊?现实生活中什么时候我们需要用到后进先出呢?

这里就不回答了,自己想想应该能明白

分析2:

 因为我们说了stack呢,主要是我用这个类给大家讲一下栈结构。那开发里面以后我们要用Queue去做对吧?

案例题目:

准备一个Stack集合,将数据11,22,33,44,55依次入栈并打印(那意味着我们是不是得new这个类对象还得调用这个类中提供的入栈方法,打印),然后查看栈顶元素并打印,然后将栈中所有数据依次出栈并打印。(那意味着说我们得借用Stack类,那借用stack类是不是得查相关的方法入栈的,然后查看栈顶的?出栈的方法是不是得查一下,)

再准备一个Stack对象,将数据从第一个栈中取出来,放到第二个栈中,然后再从第二个栈中取出并打印。

(7) 其中Vector类的底层是采用动态数组进行数据管理的,该类与ArrayList类相比属于线程安全的类,效率比较低。我们现在一般不用,因为Vector类已经被ArrayList类已经取代了

这里可能会涉及到一个笔试考点就是:Vector类和ArrayList类之间的关系是什么?

Vector类属于线程安全类,效率比较低;ArrayList类属于线程不安全类,但效率高(这两个类的关系有点和StringBuilder类和StringBuffer类之间的关系查不多,可以对比着记)

5.2 常用的方法

List集合里面这些常用方法每个实现类其实是不是都可以继承和使用?对不对?然后各个实现类的内部是不是又可以有自己独有的一些方法?对不对?那么课堂上呢?我们给大家呢讲一下统一的方法。至于各个实现类,内部各自的方法,大家课下自己可以去探索和使用一下,明白了吧

5.2.1 List集合中增加方法的使用 

方法void add(int index,E element) 在代码当中的使用

 5.2.2List集合中查找方法的使用 

对方法E get(int index) 在代码中的体现

下面这张图有一个小细节:

在Java编程中,length 和 size 是用于获取不同类型集合或数组长度的属性或方法,它们有不同的使用场景:

  1. length 属性:适用对象:数组(例如,int[]String[]Object[]等)
  2. size() 方法适用对象:实现了Collection接口的集合类(例如,ArrayListLinkedListHashSet等),以及String类(虽然String本质上不是集合,但它也提供了size()length()方法来获取字符数,但通常更常用length()

 

方法int indexOf(Object obj)int lastIndexOf(Object obj)在代码当中的使用

5.2.3 List集合中修改方法的使用 

方法E set(int index,E element)在代码中的使用,(返回的类型是是被修改位置的原始原有元素的类型)。

5.2.4 List集合中删除方法的使用

方法E remove(int index)在代码中的使用

 

 补充上面图片中的内容

5.2.5 List集合中子集合获取的使用  

对方法List<E>  subList(int formIndex,int toIndex)在代码当中的使用

6 Queue集合(重点) 

6.1 基本概念(Queue是一个接口,需要借助实现类来new对象)

(1)java.util.Queue集合是Collection集合的子集合,与List集合属于平级关系。

(2)该集合主要用于描述具有先进先出特征的数据结构,叫做队列(first in first out)。

(3)该集合主要实现类是LinkedList类,因为 该类再增删方面比较有优势。

6.2 常用的方法

案例题目:

准备一个Queue集合,将数据11,22,33,44,55依次入队并打印,然后查看队首元素并打印,然后将队列中所有数据依次出队并打印。 

总结: 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值