面向对象一

131 阅读8分钟

面向对象一

1. 面向过程 vs 面向对象

  • 不管是面向过程、面向对象,都是程序设计的思路。
  • 面向过程:以函数为基本单位,适合解决简单问题。比如:开车
  • 面向对象:以类为基本单位,适合解决复杂问题。比如:造车
  • 相辅相成的。面向对象离不开面向过程!

面向过程: - 以函数为组织单位。 - 是一种“执行者思维”,适合解决简单问题。扩展能力差、后期维护难度较大。

面向对象: - 以为组织单位。每种事物都具备自己的属性行为/功能。 - 是一种“设计者思维”,适合解决复杂问题。代码扩展性强、可维护性高。

2. 类、对象

面向对象编程的两个核心概念

  • 类:具有相同特征的事物的抽象描述,是抽象的、概念上的定义
  • 对象:实际存在的该类事物的每个个体,是具体的,因而也称为实例(instance)
  • 面向对象完成具体功能的操作的三步流程(非常重要)
步骤1:创建类,并设计类的内部成员(属性、方法)
步骤2:创建类的对象。比如:Phone p1 = new Phone();
步骤3:通过对象,调用其内部声明的属性或方法,完成相关的功能
  • 对象的内存解析
    • 创建类的一个对象;创建类的多个对象;方法的调用的内存解析
  • Java中内存结构的划分
    • Java中内存结构划分为:虚拟机栈、堆、方法区;程序计数器、本地方法栈
    • 虚拟机栈:以栈帧为基本单位,有入栈和出栈操作;每个栈帧入栈操作对应一个方法的执行;方法内的局部变量会存储在栈帧中。
    • 堆空间:new 出来的结构(数组、对象):① 数组,数组的元素在堆中 ② 对象的成员变量在堆中。
    • 方法区:加载的类的模板结构。

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 递归方法

方法自己调用自己的现象就称为递归,分为直接递归、间接递归

  • 对比:相较于循环结构,递归方法效率稍低,内存占用偏高。
  • 递归方法包含了一种隐式的循环
  • 递归方法会重复执行某段代码,但这种重复执行无须循环控制。
  • 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,停不下来,类似于死循环。最终发生栈内存溢出
  1. 递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环慢的多, 所以在使用递归时要慎重。
  2. 在要求高性能的情况下尽量避免使用递归,递归调用既花时间又耗内存。考虑使用循环迭代

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 类的实例变量的赋值过程(重要)

  1. 在类的属性中,可以有哪些位置给属性赋值? ① 默认初始化; ② 显式初始化; ③ 构造器中初始化;

④ 通过"对象.方法"的方式赋值; ⑤ 通过"对象.属性"的方式赋值;

  1. 这些位置执行的先后顺序是怎样? ① - ② - ③ - ④/⑤

10.2 JavaBean

所谓JavaBean,是指符合如下标准的Java类:

  • 类是公共的
  • 有一个无参的公共的构造器
  • 有属性,且有对应的get、set方法