面向对象一
1. 面向过程 vs 面向对象
- 不管是面向过程、面向对象,都是程序设计的思路。
- 面向过程:以函数为基本单位,适合解决简单问题。比如:开车
- 面向对象:以类为基本单位,适合解决复杂问题。比如:造车
- 相辅相成的。面向对象离不开面向过程!
面向过程: - 以
函数为组织单位。 - 是一种“执行者思维”,适合解决简单问题。扩展能力差、后期维护难度较大。
面向对象: - 以
类为组织单位。每种事物都具备自己的属性和行为/功能。 - 是一种“设计者思维”,适合解决复杂问题。代码扩展性强、可维护性高。
2. 类、对象
面向对象编程的两个核心概念
- 类:具有相同特征的事物的抽象描述,是
抽象的、概念上的定义 - 对象:实际存在的该类事物的
每个个体,是具体的,因而也称为实例(instance)。 - 面向对象完成具体功能的操作的三步流程(非常重要)
步骤1:创建类,并设计类的内部成员(属性、方法)
步骤2:创建类的对象。比如:Phone p1 = new Phone();
步骤3:通过对象,调用其内部声明的属性或方法,完成相关的功能
- 对象的内存解析
- 创建类的一个对象;创建类的多个对象;方法的调用的内存解析
- Java中内存结构的划分
- Java中内存结构划分为:
虚拟机栈、堆、方法区;程序计数器、本地方法栈 - 虚拟机栈:以栈帧为基本单位,有入栈和出栈操作;每个栈帧入栈操作对应一个方法的执行;方法内的局部变量会存储在栈帧中。
- 堆空间:new 出来的结构(数组、对象):① 数组,数组的元素在堆中 ② 对象的成员变量在堆中。
- 方法区:加载的类的模板结构。
- Java中内存结构划分为:
3. 类的成员之一:属性(或成员变量)
- 属性 vs 局部变量
- 声明的位置不同(声明在类内,方法外的变量;声明方法、构造器内部的变量)
- 内存中存放的位置不同(随着对象的创建,存储在
堆空间中;存储在栈空间中) - 作用域(整个类中有效;在对应方法或构造器中有效)
- 权限修饰符不一样(可以有;一定不能有)
- 初始化值(有默认初始化值;没有默认初始化值)
- 生命周期不同(随着对象创建而创建,消亡而消亡;随着方法对应的栈帧入栈,局部变量会在栈中分配;随着方法对应的栈帧出栈,局部变量消亡。)
- 属性 <=> 成员变量 <=>field <=> 字段、域
4. 类的成员之二:方法
方法的理解:方法是类或对象行为特征的抽象,用来完成某个功能操作。
方法的好处:实现代码重用,减少冗余,简化代码
-
方法的声明:权限修饰符 返回值类型 方法名(形参列表){ // 方法体}
- 重点:返回值类型、形参列表
-
return关键字的使用
- 作用1:结束一个方法
- 作用2:结束一个方法的同时,可以返回数据给方法的调用者 (方法声明中如果有返回值类型,则方法内需要搭配return使用)
-
返回值:
- 无返回值类型:使用void表示即可。比如:System.out.println(x)的println(x)方法、Arrays的sort()
- 有具体的返回值类型:需要指明返回的数据的类型。可以是基本数据类型,也可以引用数据类型 需要在方法内部配合使用"return + 返回值类型的变量或常量" 比如:Math.random()、new Scanner(System.in).nextInt()等
-
[经验]我们在声明方法时,要不要提供返回值类型呢? 根据方法具体实现的功能来决定。换句话说,具体问题具体分析
5. 再谈方法
5.1 方法的重载(overload)
定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。 满足这样特征的多个方法,彼此之间构成方法的重载。
-
方法的重载的要求:“两同一不同”(同一个类,同一个方法名;形成列表不同(参数个数不同,类型不同))
- 方法的重载与形参的名、权限修饰符、返回值类型都没有关系
-
调用方法时,如何确定调用的是某个指定的方法呢?
- ① 方法名 ② 形参列表
5.2 可变个数形参的方法
在调用方法时,可能会出现方法形参的类型是确定的,但是参数的个数不确定。此时,我们就可以使用可变个数形参的方法
- 格式:(int ... args)(参数类型 ... 参数名)
- ① 可变个数形参的方法在调用时,针对于可变的形参赋的实参的个数可以为:0个、1个或多个 ② 可变个数形参的方法与同一个类中,同名的多个方法之间可以构成重载 ③ 特例:可变个数形参的方法与同一个类中方法名相同,且与可变个数形参的类型相同的数组参数不构成重载。 ④ 可变个数的形参必须声明在形参列表的最后 ⑤ 可变个数的形参最多在一个方法的形参列表中出现一次
5.3 方法的参数传递机制:值传递(重点、难点)
实参给形参赋值的过程
如果形参是基本数据类型的变量,则将实参保存的数据值赋给形参。 如果形参是引用数据类型的变量,则将实参保存的地址值赋给形参。
形参:在定义方法时,方法名后面括号()中声明的变量称为形式参数,简称形参。 实参:在调用方法时,方法名后面括号()中的使用的值/变量/表达式称为实际参数,简称实参。
5.4 递归方法
方法自己调用自己的现象就称为递归,分为直接递归、间接递归
- 对比:相较于循环结构,递归方法效率稍低,内存占用偏高。
- 递归方法包含了一种
隐式的循环。 - 递归方法会
重复执行某段代码,但这种重复执行无须循环控制。 - 递归一定要向
已知方向递归,否则这种递归就变成了无穷递归,停不下来,类似于死循环。最终发生栈内存溢出。
- 递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环
慢的多, 所以在使用递归时要慎重。- 在要求高性能的情况下尽量避免使用递归,递归调用既花时间又
耗内存。考虑使用循环迭代
6. 对象数组
数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用类型中的类时,我们称为对象数组。
- String[] ;Person[] ; Customer[]
7. package、import关键字的使用
- package:指明声明的类所属的包。
- import:当前类中,如果使用其它包下的类(除java.lang包),原则上就需要导入。
8. oop(面向对象)的特征之一:封装性
Java规定了4种权限修饰,分别是:private、缺省、protected、public。 我们可以使用4种权限修饰来修饰类及类的内部成员。当这些成员被调用时,体现可见性的大小。
开发中4种权限使用频率的情况:
比较高:public、private
比较低:缺省、protected
举例:
场景1:私有化(private)类的属性,提供公共(public)的get和set方法,对此属性进行获取或修改
场景2:将类中不需要对外暴露的方法,设置为private
场景3:单例模式中构造器private的了,避免在类的外部创建实例。(放到static关键字后讲)
上理论:程序设计的原则之一
理论上:
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
(Java程序通常以类的形态呈现,相关的功能封装到方法中。)
低耦合:仅暴露少量的方法给外部使用,尽量方便外部调用。
(给相关的类、方法设置权限,把该隐藏的隐藏起来,该暴露的暴露出去)
通俗的说:把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
9. 类的成员之三:构造器
如何定义:权限修饰符 类名(形参列表){}
构造器的作用:① 搭配上new,用来创建对象 ② 初始化对象的成员变量
- 构造器声明的格式:权限修饰符 类名(形参列表){}
- 创建类以后,在没有显示提供任何构造器的情况下,系统会默认提供一个空参的构造器,且构造器的权限 与类声明的权限相同。
- 一旦类中显示声明了构造器,则系统不再提供默认的空参的构造器。
- 一个类中可以声明多个构造器,彼此之间构成重载。
10. 三个小知识
10.1 类的实例变量的赋值过程(重要)
- 在类的属性中,可以有哪些位置给属性赋值? ① 默认初始化; ② 显式初始化; ③ 构造器中初始化;
④ 通过"对象.方法"的方式赋值; ⑤ 通过"对象.属性"的方式赋值;
- 这些位置执行的先后顺序是怎样? ① - ② - ③ - ④/⑤
10.2 JavaBean
所谓JavaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法