JAVA学习笔记随记2(面向对象中级)

现在开始学习一些java面向对象中不太容易的东西了,加油吧!

(0^_^0)

首当其冲的便是包的感念和使用。

包的出现其实是为了更好的管理类,其本质就是一些文件夹和目录,同名的类不能同时出现,但如果两个同名的类在不同的包下则可以共存。相当于给每个类分配了一个地址,虽然类名是一样的,但地址绝对不同。
而包的出现也使得什么时候能够使用包里的内容,什么时候不能使用,这就涉及到了访问修饰符的知识。以及需要使用某个包里的内容应该怎么办之类的,这之后详说。

包的命名

只能包含数字,下划线,字母和圆点(.),不能包含关键字和保留字。
注意圆点隔开是不同的文件夹和目录,所以圆点隔开的每一层目录都必须遵守上述规则。
命名规范:一般是小写字母+圆点,要有具体含义。

打包和导包

引入包:我们引入包的目的是使用包中的类,所以有两种引入包的形式,
注意,同一个包中的类,不需要进行导包,只有包不同的类才需要导包。根据相对寻址,优先在本包中寻找类。所以同一个包中的类不需要导包。
第一种:

import 包名.类名
例如:import java.util.Scanner

第二种

import 包名.*
例如:import java.util

其中第一种是指定导入某个包中的某个类,第二种是将该包中的所有类都导入。
为了效率等因素,推荐第二种(idea中有自动导包的功能,所以直接用就行,不需要自己手动导包,想起了dev只用万能库....懒人是这样的。)
打包:打包的目的可以说是给该类分配一个地址,方便其他类的使用
语法如下:

package 包名

打包和导包有一些细节要求,打包指令必须是该java代码的第一条指令且只能有一个,而导包指令则须在类定义之前,可以有多个且无顺序要求。
对打包和导包进行一个小结吧,打包和导包都是在面向对象语言总避免类的重复和更好管理类而存在的,一个类可以没有不再任何一个包里,但这样其他类就不能使用和调用它,这也就失去了面向对象的价值了。一个类如果想调用非本包里的其他类的话,必须通过导包操作,将想要引用的类导入代码中才能使用。物以类聚,使用时各处借用,这也是面向对象的语言的魅力吧。

访问修饰符

早就接触到这个东西了,但一直不是那么理解,还有子类没有学习,等学习完子类,对这个知识点理解的应该也就能更深了。
首先最重要的就是这个图了。
image
感觉这个挺常考的,背的话,需要横着背和纵着背。
首先是各自顺序问题,访问修饰符从开放到限制依次是:public,protected,默认,private
对应的范围从开放到限制依次是:同类,同包,子类,不同包
这里可以简单思考下子类介于同包和不同包中间的缘由。(因为还没有开始学继承和子类,所以都是在瞎逼逼....)
子类应该是可以在不同包中继承的,即一个类的父类与当前类不同包,这样说明了子类的范围是要大于小于同包,但和纯粹的不同包又不同,因为毕竟子类也建立了一个新的关系。
两个交叉背的话,竖着背的话
public到不同包,或全部。
protected到子类。
默认到同包。
private到同类,或只有本身。
横着背的话这样:
同类的到private。
同包的话到默认。
子类的话到protected
不同包的话到public。
反复记,遇到一次,记一次,回想一次,总会记住的。
最后补充一个小细节:这四个访问修饰符都可以用来修饰属性,方法。
但用来修饰类的话,只有public和默认两种。

封装,继承和多态

面向对象编程三大特征:封装,继承和多态。

封装

封装介绍:
封装就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(方法)才能对数据进行操作。
封装的好处:
1.隐藏实现细节.
2.可以对数据进行验证,保证合理安全。
封装步骤:
1.将属性私有化。2.提供两个共有的set和get方法。
PS:封装快捷键alt+insert,和生成构造器的快捷键在一个页面内。
封装与构造器:
封装的优点便是对属性进行保护和验证,使得数据始终在我们的控制范围内进行处理。
但常规的构造器便直接对我们的属性进行初始化,这时就有可能出现数据初始化不规范的情况,越过了我们set和get方法,这与我们封装的初衷相悖。
这个时候不如在构造器中调用我们的set方法。着既使用了构造器,又实现了数据的保护。

继承

继承主要解决代码复用性问题(代码重复使用),避免冗余代码。
继承基本介绍:
继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所用的子类不需要定义这些属性和方法,只需要通过extends声明继承父类即可。
示意图如下:
image
整个继承的示意图就像一个树一样,子类拥有父类所有的属性和方法,还有独属于自己的个性化的属性和方法。子类的子类仍叫做子类,父类的父类仍叫做父类。
继承使用方法:

子类 extends 父类命
{

}

继承的细节:
1.子类继承了父类所有的属性和方法,但有访问修饰符限制的属性和方法不能在子类直接访问,必须通过子类能够访问的方法进行访问。
原本以为子类就是父类的复制粘贴,但还是有区别的,忘了访问修饰符这一回事了,子类虽然继承了父类所有的属性和方法,但有的没有“所有权”,只有“使用权”,即使在其他类眼里,子类有父类所有的东西,但子类本身并不能为所欲为,还是要受到父类一定的限制的。
2.子类必须调用父类的构造器,完成父类的初始化。
也就是说,对象的初始化是从上往下一步步传递下来的。无论子类的构造器是怎么样的,都是先通过父类构造器完成对象的初始化,接下来再通过子类的构造器。
3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下都会调用父类的无参构造器,当父类不提供无参构造器时,则必须在子类构造器中用super去指定使用父类的哪个构造器去完成对父类对象的初始化,否则,编译不会通过。
2的引申,默认是调用父类的无参构造器,若父类没有无参构造器,则必须在子类中用super指定使用父类的哪个构造器。super的介绍还没学,先记住。
4.如果希望使用父类的某个构造器,可以使用super显式调用。使用格式:

super(参数列表)

5.super在使用时,必须放在构造器的第一行(super只能在构造器中使用)。
6.super()和this()都只能放在构造器第一行,故两者不能同时出现。
7.java中所有类都是Object类的子类,Object类是所有类的超类,基类,父类。
8.父亲构造器的调用不限于直接父亲,将一直往上追溯直到Object类。
9.子类最多继承一个父类,即java中是单继承机制。
(如何让A类继承B类和C类,可以让C类继承B类,再让A类继承C类。)
10.不能滥用继承,子类和父类中之间必须满足is-a关系。
继承本质内存
image
当加载一个类时,首先是先将其父类,一级一级的加载进方法区,之后在堆中对每个类都创建中间,加载其中的属性,当需要用到其中的某个属性时,会从子类一级一级往上查找,直到找到第一个与之相对应的属性(不管能不能访问),能访问则访问,不能访问报错。

super关键字

1.super关键字代表父类的引用,适用于访问父类的属性,方法,构造器。
2.对于父类属性和方法的引用,必须是当前子类有权限访问的才可。否则报错。
3.访问父类的构造器,必须放在当前子类构造器的第一句,和this只能出现一个。
4.调用父类构造器的好处,父类初始化父类的属性,子类初始化子类的属性,分工明确。
5.当父类和子类的方法或属性同名时,若想访问父类的属性或方法,必须通过super访问,若无同名,则用super,this和默认效果一样。
6.suoper的访问不限于直接父类,会一直沿着父类网上找,满足就近原则,找到能访问则访问,不能访问则报错。
7.关于this和super的区别,记住this是本类的引用,super是父类的引用,this每次都是从当前类开始往上找的,super每次都是从父类开始网上找的,super无外乎就是跳过了当前类而已。

方法重写override

基本介绍:
方法覆盖(重写)就是子类有一个方法,和父类的某个方法,名称,返回类型,参数一样,我们就说子类的这个方法重写(覆盖)了父类的方法。
满足条件如下:
1.子类的方法名称和参数列表必须完全一样。
2.子类的方法返回类型和父类的方法的返回类型一样,或是其子类。
3.子类的方法不能缩小父类方法的访问权限。
4.重载和重写的比较
image
简单来及,就是重载只能在本类中,方法名必须一致,参数列表必须不同,对其他无要求。
重写发生在父子类中,方法名,参数列表必须一致,返回类型相同或子类的返回类型是父类返回类型的子类,访问权限的话子类不能缩小父类的访问权限。

多态

多态的基本介绍:

多态就是多种状态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

多态的具体体现:

1.方法的多态,重写和重载就体现了多态。
例如:方法的重载,都是同一个方法名,却有多个不一样的状态。(之前讲过)
2.对象的多态,理解如下:
(1)一个对象的编译类型和运行类型可以不一致。
(2)编译类型在定义对象时,就确定了,不能改变。
(3)运行类型可以改变。
(4)编译类型看定义=号的左边,运行类型=号的右边。
对象多态的前提是两个对象(类)存在继承关系。
对象多态比方法多态还复杂的多,下面时对象多态的两种形式。

向上转型。

1.本质:父类的引用指向了子类的对象。
2.语法:

父类类型 引用名=new 子类类型();

3.特点及注意事项:
(1)可以调用父类中的所有成员。
(2)但是不能调用子类的特有成员。
(#)因为在编译阶段,能调用哪些成员,是由编译类型决定的。
(3)最终运行效果,看子类(运行类型)的具体实现,即调用时,按照从子类(运行类型)开始查找方法,然后调用,规则同前面讲的调用方法一致。
首先说说怎么记这个向上类型,我们可以从堆那出发,因为new是从堆区开辟空间,然后引用指向一个父类的引用,所以从堆出发,指向父类,是向上转型。之后编译类型和运行类型,分开记,因为在不同阶段起不同作用,在编译阶段,只能调用当前父类的所有东西,但当运行时就不管了,还是从子类开始查找。(也就是说如果想调用子类的方法,必须子类和父类有重写,才能通过编译,然后运行子类的方法。)

向下转型

1.语法:

子类类型 引用名=(子类类型)父类引用

2.只能强转父类的引用,不能强转父类的对象。
3.要求父类的引用必须指向的是当前目标类型的对象。
4.当向下转型后,可以调用子类类型中所有的成员。
向下转型怎么理解,记的话还是从引用开始记,向上转型是子类对象给父类引用,向下转型是父类引用强转成子类引用,但注意必须满足父类引用本身指向的对象类型就得是当前转成的子类引用。向上可以兼容,向下必须精确。

属性的多态

之前说的都是对象对于方法引用的多态,对于属性而言,没有重写的说法,重写只能用于方法中。
对于属性而言,属性的值只关注于编译类型。

instanceOf

语法

某个类的引用 instanceOf 类名

用于判断对象的运行类型是否为xx类型或为xx类型的子类。

动态绑定机制

1.当调用对象方法时,该方法会和该对象的内存地址/运行类型相绑定。
也就是说,在调用方法时,一旦遇到新的方法,都会从运行类型所在的类一级一级往上找。
2.当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。
编译类型只是给对象属性的查找提供了一个起点,之后跑到哪里,就用哪里的属性。
感觉方法都是一直绑定或者说有保护的,而属性则没有,随遇而安。

多态的应用

1.多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型。
2.多态参数
方法定义的形参为父类类型,实参类型允许为子类类型。

Object类详解

Object作为所有类的超类,有一些基本的方法值得我们学习和记住。

equals方法

==的用法

==是一个比较运算符
1.既可以判断基本类型,也可以判断引用类型。
2.如果判断的是基本类型,判断的是值是否相等。
3.如果判断的是引用类型,判断的是地址是否相等,即指向是否是同一个对象。

equals方法

4.equals是Object类的方法,只能判断引用类型。
5.默认判断的是地址,子类中往往重写该方法,用于判断内容是否相等,比如Inter,String。

hashCode方法

1.提高具有哈希结构的容器的效率。
2.两个引用,如果指向的是同一个对象,则哈希值一定相同。
3.两个引用,如果指向的是不同对象,则哈希值大概率不同。
4.哈希值有地址经过某种映射得到,不能和地址等价。
5.后面在集合中,若hashCode有需要,也会重写。

toString方法

1.基本介绍
默认返回:全类名(包名+类名)+@+哈希值的十六进制
子类中往往重写toString方法,用于返回该对象的属性信息。(快捷键alt+insert)
2.当直接输出一个对象时,toString方法会被默认调用。

finalize方法

1.当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作。
2.什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁对象之前,会先调用finalize方法。
3.垃圾回收机制的调用,是由系统决定的(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制。
4.实际使用中,几乎不会使用finalize,重在理解。

posted @ 2023-04-28 10:20  逆天峰  阅读(21)  评论(0编辑  收藏  举报
作者:逆天峰
出处:https://www.cnblogs.com/gcfer//