本文是根据B站up主青空の霞光的JavaSE教程所整理的查漏补缺知识点笔记,有所简陋,希望能帮到大家。有错误希望大家指正。持续更新中… 注意:读此笔记需有一定的Java基础。
一、断点调试
在Java代码旁用鼠标进行点击标点,然在工作台console导航部分进行断点测试,就可以知道程序进行的每一步过程吧。
二、类变量的使用
在声明了类变量之后,在主方法中可以通过类命.类变量名或者实例化类之后通过,对象名.类变量名来进行访问。
三、代码块
代码块可以理解为只有方法体的方法,多个构造器中都有相同的语句。可以使用代码块进行初始化
四、封装
隐藏了功能的实现细节,实现步骤,首先将变量私有化,然后使用set、get方法,set、get方法可以配合构造器使用。
五、继承
1.父类私有的方法和变量是不可以访问的,需要间接的通过公有的方法去访问。 2.当子类继承了父类的构造器之后,实例化子类的时候,会将父类的构造器的内容同样调用。 3.子类在调用自己的随便哪个构造器的时候,都会调用父类的无参构造器。如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。 4.假如实例化了类,然后要使用一个变量,但父类即父父类,都有这个属性,那么就自下向上查找输出。即首先看子类是否有该属性,如果子类有这个属性,并且可以访问,则返回信息。如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息。
六、多态
在方法里面使用其他类的属性,相当于理解成在参数部分就直接实例化了,然后后面就通过实例化的名字来引用里面的方法。 1.方法的多态,通过重载和重写就可以体现。 2.对象的多态,(1)一个对象的编译类型和运行类型可以不一致(2)编译类型在定义对象时,就确定了,不能改变(3)运行类型是可以变化的.(4)编译类型看定义时=号的左边,运行类型看=号的右边 Animal animal = new Dog( );父类的引用指向了子类的对象,编译类型是父类的,运行类型是子类的。 下面使用animal.cry运行的时候,看是谁的运行类型,就引用谁的
向上转型特点:编译类型看左边,运行类型看右可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员;最终运行效果看子类的具体实现!(此时就可以解决为什么不直接实例化子类的疑问了,区别在于不能引用子类的特有的方法),存在的意义就是当多个子类指向同一个父类的时候,都要调用某个方法,向上转型可以保持方法里 参数的统一性。意义就是。个父类的多个子类声明的对象都放置在一个数组中 。
向下转型:Cat cat = (Cat) animal;需要与Animal animal = new Dog( );一起用转换的是animal的类型,animal原先是父类的引用。指向了cat,然后通过向下转型强制在变一下,姐就可以用子类的特有方法,特有方法看左边。
七、string与stringbuild
string不是基本的对象,类似于实例化str,但是省略了的。所不是基本类型就不可以用=进行大小的比较。当两个字符串进行相加的时候,那么就会重新的定义一个对象。那么我们要达到可以在字符串后面随意添加但又不重新的实例化对象的目的,就可以使用stringBuilder类。进行实例化对象之后,就会有添加字符串的方法,例如append等
八、访问控制
九、接口
接口中可以使用default来默认实现这个类,后面就可以直接调用这个接口进行使用。接口中的变量默认是final类型的
十、内部类
内部类的引用方法,首先在一个类中声明一个内部类之后,在主方法里面实例化格式,先实例化大类 大类.内部类 名字 = 大类实例化的名字.new 内部类()
静态内部类的实例化: 大类名.内部类 名字 = new 大类.内部类()
匿名内部类就是在实例化抽象类的时候,如果仅仅只是一个抽象的类方法的话,是无法实例化的,这个时候就要在实例化抽象类的时候实现里面的方法。就连接口的时候也可以这样用。
十一、lambda表达式
同上面的匿名内部类一样,但可以通过lambda表达式进行简化,但前提是接口中只有一个类,多个则不适用。只能访问外部的final类型的变量。
写法: 接口名 名字 = 方法参数() -> {方法的实现}
十二、 枚举类
通过定义一个枚举的类,类里面写出所有的想要枚举出来的东西,然后在其他页面定义变量的时候,通过枚举的类型进行定义,类似于 public 枚举类型 变量名 这样的定义方法,然后在实例化的时候方法要写入东西进去的时候,直接写入枚举名. 之后,可写入的名字就会提示出来。里面也可以直接写入方法,然后通过.来将方法使用。
十三、基本数据类型的包装类
java中的基本数据类型的包装类的作用是: 1.作为和基本数据类型对应的类类型存在,方便涉及到对象的操作。 2.包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。 意义在于会涉及到时间复杂度的要求 变成对象之后进行比较不能用等号了,就需要使用equals,这个时候就可以直接用包装类的变量用 . (点)引出方法。但-127 到+128之间的数值是他已经给定了的对象地址,此时直接用==比较也行。如果integer之后的变量名加上了一个基本数据类型之后,就会自动拆箱,变成普通的基本类型,即而如果使用包装类来进行运算,或是赋值给一个基本类型变量,会进行自动拆箱。变成基本类型。
十四、异常的抛出与捕获
在编写方法的时候,我们觉得方法可能存在会出错的情况,那么我们就要在方法后加上throws进行异常的抛出,然后在调用的时候使用try…catch进行异常的捕获。方法里面再列出会出现异常的情况,例如 if(b=O)throw new Exception("0不能做除数!");//创建异常对象并抛出异常 finally写在catch之后,无论是否出现异常。都会运行finally中的语句。
十五、泛型
感觉泛型就像是个类型占位符或是类型变量, 创建的时候指定所需要的类型。可以帮助快速确认数据类型。 泛型的使用 在声明的类名的后面加上<>括号中为加上的泛型的名称,有几个泛型就加几个,然后在不确定数据类型的变量的前面加上泛型的标识,方法中的参数也加上泛型标识,在一切可能用到该变量的地方加上泛型标识。注意,在实例化对象的时候,就需要将泛型的类型指出来了。例如:
泛型不可用在静态变量上,因为需要在实例化对象的时候指出泛型的类型。泛型的定义不能为基本数据类型,因为泛型的本质就是返回到object上面,然后再转换成我们需要的类型,用的是包装类型,所以泛型标识里面不能写基本数据类型。
静态方法和成员方法是可以自定义泛型的,在数据类型那里换成数据标识就可以了。其意义在于类上面的泛型,如果方法使用的话,那是定义在类上的泛型,要先经过类的实例化,但如果你是定义在方法上的话,就可以在引用该方法的时候将类型确认。
泛型的上界与下界,extends定义了上界之后,泛型就只能用该类型以及该类型的子类,如果super了下界,那么就只能使用该类型以及该类型以上的数据类型。
泛型还可以定义在接口上,类在继承接口的时候,有两种方法,要么就接口还是保持泛型,那么就在实例化的时候再将泛型给明确指出,要么就在接口的时候将泛型明确指出了之后,类中的泛型全部换成制定类型。
十六、数据结构之顺序表的实现
实现目的 查询数组的大小,插入数据,删除数据,给出数据返回数据的下标。
查询数据大小方法:首先定义一个变量size,然后后面调用加数据的方法的时候就让size++,在查询数据大小的方法里只需要返回size进行了。
插入数据:首先判断计加入的数据是否合法,即要么插在数据的最后,要么插在数据的中间,不能使其有空格。如果非法差插入,那么抛出错误。然后,判断数组的大小,如果超出数组的容量,就新建一个数组,将原来的数组的值赋值给新的数组。然后再将新的数组把原来的数组代替。然后,因为数组的下标是从0开始的,所以这里就不能用size与要插入的下标进行比较了,将size-1如果要插入的数据的小标小于这个值,那么该下标出以后的数据全部往后移,例如 arr[i+1]=arr[i] 即将当前下标的值给后面的下标,直到插入的小标的值小于size-1的时候,就代表已经全部向后移了一格了,注意用while循环。然后(size-1)用变量i表示,是逐渐变小的即i–,因为需要从后面将数据往后拉。然后空出来了想要插入数据的地方的下标位置后,将数据插入进去,并且size++。
删除数据:同样判断删除的数据是否非法,如果非法就抛出错误。同样是下标为基准的操作,所以要将size-1,需要将index作为变量i,当i小于size-1的时候,直接覆盖当前下标的数组的值,即arr[i]=arr[i+1] ,然后i++逐渐将后面的值前移进行覆盖。因为移除了数据,所以需要size–。
返回给出下标的值:直接在方法中返回数组下标就行,例如return arr[index]
注意:加数据与删数据,循环的时候的基准不一样,加数据的时候,是以数组的大小的下标为,即size-1为基准,size-1代表的下标逐渐往前移,数据逐渐往后移,直到size-1与给的下标不同。然而删除数据的时候,是由我们给出的下标为基准,直接将后面的数据进行覆盖,然后将我们给出的下标逐渐相加,直到与数组的大小相等的时候,代表数据已经覆盖完成。
十七、数据结构值之链表的实现
实现目的 查询数组的大小,插入数据,删除数据,给出数据的下标返回数据。
查询数据大小方法:首先定义一个变量size,然后后面调用加数据的方法的时候就让size++,在查询数据大小的方法里只需要返回size进行了。
插入数据:首先理一下链表插入数据的思路,链表有两个要素,第一要素就是自己的值,第二要素就是指向下一节点的位置。第一步 ,我们需要定义一个内部类,这个内部类代表的意思是指链表中的每一个节点类型,后续需要声明新的节点的时候,就可以用该内部类声明节点。然后可以全局声明一个node类型的头结点,头结点值为null。 第二步 ,首先判断插入的值是否合法,不合法则抛出异常。然后Node<E> node = head, temp ; 相当于声明了两个Node类型的变量,node 和 temp,其中将 head 赋值给node,也可以写成声明node变量,将head的值给了node,即Node<E> node = head 和声明temp变量,即Node temp,这样看着不易搞混。然后node作为头结点之后。要根据用户输入的要插入的下标的地方进行遍历,即为找出用户给出下标的值。让node一个一个往后挪,即node = node.next ,然后此时让Node型的变量temp,也可以理解为temp节点。让temp节点接管node遍历到的位置的后面的节点,即temp = node.next。然后node的next就可以直接实例化一个值为e的节点。即node.next = new Node<>() ,此处实例化看着可能和正常的实例化代码有所不同,但node的next在内部类中已经声明成了Nod类型,所以并没有错误吗,然后node的下一个节点已经插入了新的数据,那么就将temp上的数据链接上来。即node的下一个的下一个就是temp节点。 删除数据:同理,首先需要判断插入是否合法,不合法抛出异常。然后同上声明两个变量node和temp,然后进行遍历,遍历到给出的要删除的下标的地方,然后让变量temp接管该下标之后的节点,然后让node.next直接等于他之后的节点,即node.next = next.next.next。这样node.next直接就被覆盖了,但是在temp那里有个备份。返回temp中的e就是要删除的值。 给出下标返回数据:首先判断返回数据是否合理,不合理抛出异常。此处的node就不能等于头节点了,因为头节点应该为空,只作为一个基准,并不是任何值=下标值,所以,node的值起始值为头节点的下一个的值。然后进行遍历,直到找到各下标的值之后就返回。
十八、数据结构之栈的实现(顺序表)
入栈:入栈只能从后面逐渐一个一个的添加。首先对其容量进行判断,超出容量的进行扩容,扩容原理同上一样。因为size的大小比数据的下标的数量要大1,所以size作为下标就代表了总元素后面的,直接插入进去,然后size++。 出栈:同理如上,size要比数据的下标大1,所以返回size-1就是出来的元素,然后将size的大小减一就行,后续将入栈的时候,会根据size的数值进行覆盖。
十九、数据结构之队列的实现(顺序表)
入队:首先声明数组,用来存放数据,然后声明变量头和变量尾。当数据为空的时候,头和尾都是0。所以可以用尾部作为下标,然后添加数据。注意此处暂时不扩容,然后当队列出去的时候,头部也跟着动,最后头部和尾部达到数组的峰值,这个时候就可以用取余的方法进行一个循环覆盖。然后还需要一个语句进行判断是否已经插满,插满则不在插入,返回空值,那么需要将最后一个数据格空出来进行加1的判断,如果加上1之后除于数组的长度余数为0,那么将不再插入。 出队:同样头的下标是以0开始的,所以可以将头作为下标进行出队的数据,然后同样用取余的方法以数组的长度为一个循环。
二十、数据结构之二叉树的实现
关于二叉树,可以联想到链表,链表是一对一的关系,二叉树是一对多的关系,相当于是一个结点对应了很多的子结点。那么可以用链表的思想,声明一个结点类,即
同时可声明一个构造函数,可以在实例化结点的时候直接赋值进去。 实例化头结点,然后根据左右结点实例化然后将值插入进去。
前序遍历:从二叉树的根结点出发,到达结点时就直接输出结点数据,按照先向左在向右的方向访问。 中序遍历:从二叉树的根结点出发,优先输出左子树的节点的数据,再输出当前节点本身,最后才是右子树。 后序遍历:从二叉树的根结点出发,优先遍历其左子树,再遍历右子树,最后在输出当前节点本身。 二叉树的遍历则是根据左右结点的输出顺序从而完成几种遍历方法。
二十一、数据结构之哈希表的理解
哈希表是顺序表和链表折中的存储方法,用数的值除以哈希数组的容量取余,余数为多少则对应插在哪里,如遇重复的余数,则通过链表的特点将相同余数的值连接起来。
二十二、数据结构之二叉排序树和二叉平衡树理解
将二叉树通过排序变成二叉排序树,能够更好的对数据进行查询左子树比右子树的值要小。但要注意一点,当一堆数组中最大的那个数成了头结点,那么比它小的数就都会在左边,那么此时的二叉树和原始的二叉树没有区别了,还是需要一个一个的查询。这里就需要二叉平衡树的概念将其通过左旋和右旋变成左右高度不超过1的二叉树。 转换为平衡二叉树 步骤: 1.创建一个新节点值等于当前节点 2把当前节点的右子树设置为新节点的右子树 3.把新节点的右子树设置为当前接点的左子树的右子树 4把当前节点的值换为左自节点的值 5把当前节点的右节点设置为新节点
左左失衡通过右旋改变,右右失衡通过左旋改变
二十三、数据结构之红黑树的理解
红黑树 红黑树也是二叉排序树的一种改进,同平衡二叉树一样,红黑树也是一种维护平衡的二叉排序树,但是没有平衡二叉树那样严格(平衡二叉树每次插入新结点时,可能会出现大量的旋转,而红黑树保证不超过三次),红黑树降低了对于旋转的要求,因此效率有一定的提升同时实现起来也更加简单。但是红黑树的效率却高于平衡二叉树,红黑树也是JDK1.8中使用的数据结构!
红黑树的特性: (1)每个节点或者是黑色,或者是红色。 (2)根节点是黑色。 (3)每个叶子节点的两边也需要表示(虽然没有,但是u川也需要表示出来)是黑色。 (4)如果一个节点是红色的,则它的子节点必须是黑色的。 (5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
一个节点是如何插入到红黑树中的: 基本的插入规则和平衡二叉树一样,但是在插入后: 1.将新插入的节点标记为红色 2.如果X是根结点(root),则标记为黑色 3.如果X的parent不是黑色,同时X也不是root: 3.1如果X的uncle(叔叔)是红色 3.1.1将parent和uncle标记为黑色 3.1.2将grand parent(祖父)标记为红色 3.1.3让X节点的颜色与X祖父的颜色相同,然后重复步骤2、3 3.2如果X的uncle(叔叔)是黑色,我们要分四种情况处理 3.2.1左左(P是G的左孩子,并且X是P的左孩子) 3.2.2左右(P是G的左孩子,并且X是P的右孩子) 3.2.3右右P是G的右孩子,并且X是P的右孩子) 3.2.4右左P是G的右孩子,并且X是P的左孩子)
二十四、集合类的了解
数组与集合 相同之处: 1.它们都是容器,都能够容纳一组元素。 不同之处: 1.数组的大小是固定的,集合的大小是可变的。 2.数组可以存放基本数据类型,但集合只能存放对象。 3.数组存放的类型只能是一种,但集合可以有不同种类的元素
扩展:泛型可以为一种类类型,可以直接定义泛型的类的类型,然后在主方法那里泛型处使用定义的类的类型。
二十五、foreach的用法
格式 for(元素类型 元素变量x:遍历对象(数组或集合)){ 引用元素变量x的语句; }
二十六、迭代器
不仅仅是数组,所有的集合类都支持使用foreach循环进行遍历,也可以使用集合自带的遍历foreach即list.foreach来进行遍历。
Iterable和Iterator接口 我们之前学习数据结构时,已经得知,不同的线性表实现,在获取元素时的效率也不同,因此我们需要一种更好地方式来统一不同数据结构的遍历。由于ArrayListi对于随机访问的速度更快,而LinkedList对f顺序访问的速度更快,因此在上述的传统for循环遍历操作中,ArrayList的效率更胜一筹,因此我们要使得LinkedListi遍历效率提升,就需要采用顺序访问的方式进行遍历,如果没有迭代器帮助我们统一标准,那么我们在应对多种集合类型的时候,就需要对应编写不同的遍历算法,很显然这样会降低我们的开发效率,而迭代器的出现就帮助我们解决了这个问题。
二十七、Set集合
我们之前已经看过Set接口的定义了,我们发现接口中定义的方法都是Collection中直接继承的,因此,Set支持的功能其实也就和Collection中定义的差不多,只不过使用方法上稍有不同。 Set集合特点: 不允许出现重复元素 不支持随机访问(不允许通过下标访问)
set集合不允许随机插入数据,同时根据哈希算法进行排序的,所以插进去的数值与打印出来的数据顺序可能会不一样,但linkehashset可以保存我们的顺序,只需要将运行类型改变一下就可以了,即 以及另外一个TreeSet,也是指定排序规则。
二十八、映射Hashmap
Map映射 什么是映射 我们在高中阶段其实已经学习过映射了,映射指两个元素的之间相互“对应”的关系,也就是说,我们的元素之间是两两对应的,是以键值对的形式存在。 Map接口 Map就是为了实现这种数据结构而存在的,我们通过保存键值对的形式来存储映射关系。
映射Hashmap 当使用hashmap进行存储的阿时候,容易出现数据多的情况,那么就需要进行扩容,然后hashmap内部有相应的扩容机制,然后就算是扩容了之后,当使用哈希算法进行计算的三时候,所除得的余数相等也会造成数据聚集的情况,那么此时将运用到红黑树的知识,只存放余数相同的数据的头结点,其余的都是红黑树,然后通过二分查找,能够更快的查找到数据。当链表的长度达到8时,会自动将链表转换为红黑树,这样能使得原有的查询效率大幅度降低!当使用红黑树之后,我们就可以利用二分搜索的思想,快速地去寻找我们想要的结果,而不是像链表一样挨个去看。
先短暂了解原理。后期可以进行深入的了解,如linkehashmap等用法
map的一些使用
|