Java基础面向对象学习笔记(未完成)
Java面向对象(OOP)
学习面向对象的三条主线
1、Java中类及类的成员
2、面向对象的三大特征
3、其他关键字的使用
Java中类及类的成员
1、成员变量(或属性)
2、方法(函数)
3、构造器(或构造方法)
4、代码块(或初始化块)
5、内部类
面向对象的三大特征
封装性、继承性、多态性(+抽象性)
其他关键字的使用
this、super、abstract、interface、package、import ......
(三条主线同时推进)
面向对象
将功能封装进对象,强调具备了功能的对象,以类或对象为最小单位,考虑谁来做
面向对象中最基本的两个要素
- 类、对象
- 类:是对一类事物的描述,是抽象的、概念上的定义
- 对象:由类派生出来的,是实际存在的该类事物的每个个体,因而也被称为实例
- 万事万物皆为对象
类
- 属性:对应类中的成员变量- field-(域-字段)
- 行为:对应类中的成员方法-函数- method
- 类的创建及提供类的成员:属性和方法
- 创建类的对象-实例化类-类的实例化
- 调用类的相关结构:“对象.属性”或“对象.方法”
类中方法的声明和使用
1、方法的声明格式:
权限修饰符 返回值类型 方法名(形参列表){
//方法体
}
2、细节说明:
2.1、权限修饰符:指明所修饰的结构可被调用的范围大小
技巧:暂时声明方法时用public
2.2、返回值类型:有具体的数据类型 或 void(无返回值)
1. 根据需要选择返回值类型
2. 如果指明了具体的数据类型,则必须在方法执行的最后,返回要求的数据类型的变量或常量
3. 方法体中执行到return结束方法
4. void中也可以用return
2.3、方法名,属于标识名
2.4、形参列表:可以根据需要,声明方法时,提供形参列表。 如果需要声明多个形参,使用逗号隔开
面向对象特征之一:封装性
封装性思想的体现
- 私有化类的属性,提供get() 和set()去访问和设置
- 类中提供私有的方法,表明此方法只能在类内部中被调用
- 如果类只希望在本包内被调用,则可声明为缺省状态
- 单例模式
Java规定的四种权限修饰符——广义上封装性的体现
- 权限从小到大为:private < 缺省 < protected < public
- 具体修饰范围:
说明:任何地方:本project内有效 - 权限修饰符可以用来修饰的结构说明:
- 四种权限可以修饰类内部的成员:属性、方法、构造器、内部类
- 类本身可以使用两种权限修饰:缺省、public
说明:
修饰相应的结构,体现这个结构被调用时,可见性的大小
构造器(构造方法):Constructor
构造器的作用
- 创建类的对象
- 初始化对象的属性
使用说明
- 如果我们没显式的提供类的构造器的话,则系统会默认给类提供一个默认的构造器:无参数的
- 我们如果显式的声明类的构造器的话,格式为:权限修饰符 类名(形参列表){}
- 同一个类的构造器之间构成重载。
- 我们如果显式的提供了类的构造器,则系统不再提供默认的空参的构造器
- Java的类中一定存在构造器
构造器
-
构造器的理解
contructor :n. 建设者、建造者
contract:v. 建设、建造
contraction:n. 建设、建造 -
构造器的作用
- 搭配new关键字,创建类的对象
- 在创建对象的同时,可以给对象的相关属性赋值
- 构造器的使用说明
构造器的声明格式:权限修饰符 类名(形参列表){}
创建类以后,没有显示提供任何构造器的情况下,系统会默认提供一个空参的构造器,且构造器的权限与类的权限相同
一旦类中显示声明了构造器,系统不再提供空参构造器。
阶段小结
-
在类的属性中,有哪些位置可以给属性赋值
1默认赋值2显式赋值
3构造器中赋值
4通过“对象.方法”的方式赋值
5通过“对象.属性”的方法赋值
-
这些位置执行的先后顺序是怎样的?
1->2->3->4/5
- 以上操作在对象创建过程中可以执行的次数如何?
1、2、3只能执行一次
4、5可以多次执行
JavaBean
概念
- 类是公共的
- 有一个无参的公共构造器
- 有属性,且有对应的get、set方法
对象数组
概念
数组元素可以是基本数据类型,也可以是引用数据类型。当数组元素是引用数据类型中的类时,称之为对象数组。
面向对象特征之二:继承性
理解:
生活上:财产的继承
代码层面:
- 自上而下:定义了一个类A,在定义另一个类B时,发现B的功能包含A功能,则考虑B继承A
- 自下而上:定义了类B、C、D等,发现BCD有相同的属性方法,则可以考虑抽取出来封装到类A中,让类BCD继承类A
继承的好处
- 继承的出现,减少代码的冗余,提高了代码的复用性
- 继承的出现,更有利于代码的扩展
- 继承的出现,让类与类之间产生了 is-a 的关系,多态的使用提供了前提
- 继承描述事物间的所属关系,这种关系是 is-a 的关系。可见父类更用通用、更一般,子类更具体
继承中的基本概念
父类:superClass、超类、基类
子类:subClass、派生类
有了继承之后
子类就获取到了父类中声明的所有属性和方法
但是,由于封装性的影响,子类可能不能直接调用父类中的属性或方法
子类在继承父类之后还可以扩展自己特有的功能(增加特有的属性、方法)
extends:延展、扩展、延伸
子类和父类的理解要区别于集合与子集
不要为了继承而继承,在继承前要判断一下是否有“is a”的关系
默认的父类
Java中声明的类如果没有特殊声明其父类,则默认继承于java.lang.Object
补充
Java是支持多层继承的
直接父类、间接父类
Java中的子父类概念是相对的
Java中的一个父类可以有多的子类,但是一个子类只能有一个父类(Java的单继承性)
方法的重写(overwrite/override)
为什么需要方法的重写
子类在继承父类以后,就获取了父类中声明的所有方法。但是父类中的方法可能不太适用于子类。换句话说,子类需要对父类中继承过来的方法进行覆盖、覆写的操作。
何为方法的重写
子类对父类继承过来的方法的覆盖、覆写的操作就称为方法的重写
方法的重写应遵循的规则
【复习】方法声明的格式:
权限修饰符 返回值类型 方法名(含参列表)[throws 异常类型] {//方法体}
具体规则:
- 父类中被重写的方法与子类中重写的方法的方法名和形参列表必须相同
- 子类中重写的方法的权限修饰符不小于父类中被重写的方法的权限修饰符
- 子类不能重写父类中声明为private的方法
- 返回值类型
父类被重写方法的返回值类型是void,则子类中重写方法的返回值也必须是void
父类被重写方法的返回值类型是基本数据类型,则子类中重写方法的返回值类型必须与被重写的返回值类型相同
父类被重写的返回值类型为引用数据类型(比如类),则子类中重写方法的返回值类型可以与被重写的返回值类型相同 或 是被重写的返回值类型的子类
- 子类重写的方法抛出的异常类型可以于父类被抛出的异常类型相同或是父类被抛出的异常类型的子类
多态性
1. 如何理解多态性?
理解为一个事物的多样性
2. Java中多态性的体现:
子类对象的多态性:父类的引用指向子类的对象。(或子类的对象指向父类的引用)
3. 多态性的应用:虚方法调用
在多态的场景下,调用方法时。
编译时,认为是左边声明的父类的类型方法(即被重写的方法)
执行时,实际执行的是子类重写父类的方法。
简称:编译看左边,运行看右边
4. 多态性的使用前提:
- 要有类的继承关系
- 要有方法的重写
5. 多态的适用性:
- 适用于方法,不适用于属性
6. 多态的好处与弊端
好处:极大的减少了代码的冗余,不需要定义多个重载的方法
弊端:在多肽的场景下我们创建了子类的对象,也加载了子类特有的属性和方法。但是由于声明为父类的引用,导致我们没有办法直接调用子类特有的属性和方法
属性看编译,方法看运行
类的成员之四——代码块(初始代码块)
-
代码块(初始代码块)的作用:
用来初始化类或对象的信息(即初始化类或对象的成员变量) -
代码块的修饰:
只能使用static进行修饰 -
代码块的分类:
静态代码块:使用static修饰
非静态代码块:未使用static修饰 -
具体使用:
静态代码块: > 随着类的加载而执行(调用) > 由于类的加载只会执行一次,进而静态代码块的执行,也只会执行一次 > 作用用来初始化对象信息 > 内部可以声明变量、调用属性或方法、编写输出语句等操作 > 静态代码块的执行先于非静态代码块 > 如果有声明多个静态代码块,则按照声明的先后顺序执行 > 静态代码块内部只能调用静态的结构(即静态的属性、方法),不能调用非静态的结构(即非静态的属性、方法) 非静态代码块: > 随着对象的创建而执行 > 每创建当前类的一个实例就会执行一次非静态代码块 > 作用用来初始化对象信息 > 内部可以声明变量、调用属性或方法、编写输出语句等操作 > 如果有声明多个非静态代码块,则按照声明的先后顺序执行 > 非静态代码块内部即能调用静态的结构(即静态的属性、方法),也能调用非静态的结构(即非静态的属性、方法)
抽象类与抽象方法(或abstract关键字)
抽象方法:只有方法签名,没有方法体,包含抽象方法的类必须时抽象类
-
abstract的概念:抽象的
-
abstract可以用来修饰:类、方法
-
具体使用:
abstract修饰类: > 此类称为抽象类 > 抽象类不能实例化 > 抽象类包含构造器,因为子类对象实例化时,需要直接或间接的调用父类的构造器 > 抽象类中可以没有抽象方法,反之抽象方法所在的类一定是抽象类 abstract修饰方法: > 此方法为抽象方法 > 此方法只有方法的声明没有方法体 > 抽象方法其功能是确定的,通过方法的声明即可确定,只是不知道如何实现 > 子类必须重写父类中所有的抽象方法,方可实例化,否则还是一个抽象类,因为包含抽象方法
-
abstract不能使用的场景:
abstract不能修饰的结构: 属性、构造器、代码块等 abstract不能与哪些关键字共用(自洽): 不能用abstract修饰私有方法、静态方法、final的方法、final类。 > 私有方法不能重写 > 避免被静态方法调用 > final的方法不能被调用 > final修饰的类不能有子类
抽象类中可以有非抽象的方法,但非抽象类中不能有抽象的方法
接口
-
接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样。制定好后大家都要遵守
-
定义接口的关键字:interface
-
接口内部结构的说明:
> 可以声明: 属性必须使用使用public、static、final修饰 方法: JDK8之前:声明抽象方法,修饰为public abstract JDK8:声明静态方法、默认方法 JDK9:声明私有方法 > 不可以声明:构造器、代码块等
-
结构与类的关系:实现关系
-
格式: class A extends SuperA implements B,C{}
A相较于SuperA来说叫做子类 A相较于B,C来说叫做实现类
-
满足此关系后,说明
类可以实现多个接口 类针对于接口的多实现,一定程度上弥补了类的单继承的局限性。 类必须将实现的接口中的所有抽象方法都重写(或实现),方可实例化。否则此类必须声明为抽象类
-
接口与接口的关系:继承关系,并且可以多继承
-
接口的多态性:
> 类格式: 父类名 变量名 = new 子类对象名; > 接口格式: 接口名 变量名 = new 实现类的对象名;
-
试题:如何区分抽象类和接口
接口中的变量默认为常量(省略public static final
),方法默认为抽象方法(省略public abstract
)
内部类
定义:
一个类A定义在类B内,类A称为内部类,类B称为外部类
为什么需要内部类
当一个事物A内部,还有一个部分需要一个完整的结构B进行描述,而这个完整的结构B有只为事物A服务,不在其他地方单独使用,那么内部的完整结构B最好使用内部类。
总的来说,遵循高内聚低耦合的面向对象开发原则
内部类实例
Thread类内部声明了State类,表示线程的声明周期
HashMap类中声明了Node类,表示封装的key和value
内部类的分类:(参考变量的分类)
成员内部类:直接声明在外部类的里面
使用static修饰的,静态的成员内部类
不使用static修饰的,非静态的内部类
局部内部类:声明在方法内、构造器内、代码块的内部
匿名的局部内部类
非匿名的局部内部类
内部类的知识点
- 成员内部类的理解
- 如何创建创建成员内部类的实例
- 如何在成员内部类中调用外部流泪的结构
- 局部内部类的基本使用
关于内部类的理解
从类的角度看
- 内部可以声明属性、方法、构造器、内部类等结构
- 此内部类可以声明父类,可以实现接口
- 可以使用final修饰
- 可以使用abstract修饰
从外部类的成员的角度看
- 在内部可以调用外部类的结构,如属性、方法等
- 除了使用public、缺省权限修饰外还可以使用private和protected
- 可以使用static修饰
关于局部内部类的说明
枚举类
什么是枚举类
枚举类型本质上也是一种类,只不过这个类的对象是有限的、固定的几个,不能让用户随意创建
若枚举还有一种,则可以作为一种单例模式的实现方式
开发中的建议
- 开发中,如果针对于某个类,其实例是确定个数的。则推荐讲此类声明为枚举类。
- 如果枚举类的实例只有一个,则可以看作是单例的实现方法
关键字enum
模版
点击查看代码
public enum Color {
READ(255,0,0,"红色"),ORANGE(255,128,0,"橙色"),
YELLOW(255,255,0,"黄色"),GREEN(0,255,0,"绿色"),
CYAN(0,255,255,"青色"),BLUE(0,0,255,"蓝色"),
PURPLE(128,0,255,"紫色");
private final int red;
private final int green;
private final int blue;
private final String description;
Color(int red, int green, int blue, String description) {
this.red = red;
this.green = green;
this.blue = blue;
this.description = description;
}
@Override
public String toString() {
return super.toString()+ "(" + red + "," + green+","+ blue + ")" + "->" + description;
}
}
注解
什么是注解
注解(Annotation)是从JDK5.0开始引入,以@注解名在代码中存在。
例如
@Override
@Deprecated
@SuppressWarnings(value="unchecked")
Annotation可以像修饰符一样被使用,可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明。还可以添加一些参数值,这些信息被保存在Annotation的"name=value"对中
注解可以在类编译、运行时进行加载,体现不同的功能。
注解和注释
注解也可以看成一种注释,通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。但是注解不同于多行注释和单行注释。
- 对于单行注释和多行注释是给程序员看的
- 而注解是可以被编译器或其他程序读取的,程序还可以通过注解不同,做出相应的处理
注解的重要性
在JavaSE中注解的使用比较简单,例如标记过时的功能、忽略警告等。在JavaEE/Android中注释占据了更重要的角色,例如用来配置应用程序的各种切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。
未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3x以后也是基于注解的,Struts有一部分也是基于注解的了。注解是一种趋势,一定程度上可以说:框架 = 注解 + 反射 + 设计模式。
常见的Annotation作用
示例1:生成文档相关的注解
@author 标明开发该模块的作者,多个作者之间使用,分割
@version 标明该类模块的版本
@see 参考转向,也就是相关主题
@since 从哪个版本开始增加的
@param 对方法中某参数的说明,如果没有参数就不能写
@return 对方法返回值的说明,如果方法返回值类型是void就不能写
@exception 对方法可能抛出的异常进行说明,如果方法没有用throw显示抛出的异常就不能写
示例2:在编译时进行格式检查(JDK内置的三个基本注解)
@Override:限定重写父类方法,该注解只能用于方法
@Deprecated:用于表示所修饰的元素(类、方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings:抑制编译器警告
自定义注解
以@SuppressWarnings为参照,进行定义即可
元注解的理解
对现有的注解进行解释说明的注解
@Retention
@Retention用于指定注解的保留策略,即注解在代码运行时的生命周期。它接受一个RetentionPolicy类型的参数,包括三个选项:
RetentionPolicy.SOURCE:注解仅存在于源代码中,编译后失效。
RetentionPolicy.CLASS:注解会被保留到编译后的字节码文件中,但运行时无法获取。
RetentionPolicy.RUNTIME:注解会被保留到运行时,并且可以通过反射机制获取注解信息。
@Target
@Target用于指定注解可以应用的目标元素类型。它接受一个ElementType类型的数组参数,包括多个选项:
ElementType.TYPE:类、接口、枚举。
ElementType.FIELD:字段。
ElementType.METHOD:方法。
ElementType.PARAMETER:方法参数。
ElementType.CONSTRUCTOR:构造函数。
ElementType.LOCAL_VARIABLE:局部变量。
通过@Target可以限制注解的使用范围,使其只能应用于特定的元素类型。
@Inherited
@Inherited用于指定注解是否具有继承性。当一个注解被@Inherited修饰后,它会被子类所继承。默认情况下,注解是不具有继承性的,即子类不会继承父类的注解。
@Documented
@Documented用于指定注解是否包含在Java文档中。当一个注解被@Documented修饰后,它将被包含在生成的文档中,方便开发人员查阅
拓展:元数据
单元测试:Test
- 所在类必须是public、非抽象的,包含唯一无参构造器的
- @Test标记的方法必须是public、非抽象的、非静态的、void无返回值的、()中无参的
框架 = 注解+反射+设计模式
包装类
作用
为了使得基本数据类型具有引用数据类型的相关特征(比如:封装性、继承性、多态性),我们给各个基础数据类型提供了相应的包装类
基本数据类型对应的包装类
继承于number
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
char ->Character
boolean -> Boolean
包装类、基本数据类型转化为String
使用String.valueof函数
String 转化为 包装类、基本数据类型
使用XXX.parseXXX函数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术