Java学习 - 面向对象

本文最后更新于 2024年12月4日 凌晨

面向对象

何为面向对象?

面向对象是一种软件开发方法,一种编程范式[1]。面向对象编程时一种以“对象”为核心的编程范式,而Java是一门典型的面向对象编程语言。通过类和对象的概念,将现实世界的实体机器行为映射到程序中。

  • 类 (Class): 类是对象的模板或蓝图,定义了对象的属性和方法。

  • 对象 (Object): 对象是类的实例,具体表现为程序中具有独立状态和行为的实体。

  • 方法 (Method): 定义对象的行为(功能)。

  • 属性 (Attribute): 描述对象的特征(数据)。[2]

这样解释程序结构与事物之间的联系是十分符合人的逻辑的,因此人们可以通过这个形式,给予程序结构各种不一样的设计。

与面向过程的区别

面向过程将一个任务中所需要用到的方法拆开并进行使用。而面向对象则是创建一个个对象,并基于对象与对象之间的关系和他们内部的一些行为和方法来完成任务。

可以看出来,面向过程是针对任务的,相较面向对象会更加一目了然,并且少了很多步骤,因此面向过程的执行效率比面向对象要快。但是代码设计更加单一,难以管理和进行扩展重构,缺乏结构性和灵活性。

面向对象的三大核心特征:封装,继承,多态

封装:

将数据与方法集合(封装)到一起,使其形成一个独立的实体。数据在实体的内部,可以隐藏内部细节,只对外部开放一些接口来与外部产生联系。

优点:

  • 减少耦合:确保了实体为独立的,因此一个实体的修改并不会对其他实体本身造成影响。
  • 方便性能检测: 因为试图独立且扮演着各自的角色与行为,因此在检测影响性能的因素时能够更加清晰地确定哪里出了问题。
  • 降低构建大型系统的风险: 系统的崩溃也许并不是因为这个独立的实体造成的。
  • 提高安全性: 有效隐藏了实体的内部信息,降低受到更改和攻击的风险。
  • 符合直觉

继承:

实现了A is a B这样的关系。指的是一个类(子类)可以从另一个类(父类)中获取属性和方法,从而实现代码复用和扩展。

  1. 父类(超类 / 基类): 提供属性和方法的类。
  2. 子类(派生类): 继承父类的类,可以直接使用父类的属性和方法,也可以添加自己的功能。

比如 ShapeRectangleSquareShape \rightarrow Rectangle \rightarrow SquareAnimalRabbitAnimal \rightarrow RabbitVehicleTrainVehicle \rightarrow Train​等等。

继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。[3]

优点:

  • 代码复用: 子类可以直接复用父类的代码,无需重复编写。

  • 易于扩展: 新的功能可以通过扩展现有类实现。

  • 逻辑清晰: 类的层次关系体现了现实世界中“是某种类型”的逻辑。

局限性:

  • 单继承限制: Java 不支持类的多继承(但可以通过接口实现类似功能)。

  • 过度继承问题: 如果层次过深,子类和父类之间的关系复杂,会导致代码维护困难。

  • 强耦合: 子类与父类高度耦合,父类的修改可能影响所有子类。

多态:

指同一个方法或操作在不同对象中表现出不同的行为[2]。多态主要有两种形式:

  1. 编译时多态(静态多态): 方法重载(Method Overloading),在同一个类中定义多个拥有相同名称但参数类型或数量不同的方法。

    • 编译器便决定
    • 不涉及继承或类层次结构
  2. 运行时多态(动态多态): 方法重写(Method Overriding),在不同类中,根据实际引用的对象类型调用方法(父类引用指向子类对象)

    • 运行期确定
    • 需要继承或实现接口
    • 父类引用可以指向子类对象

优点:

  • 提高代码复用性: 子类可以直接使用父类的方法或重写其行为,减少代码重复。

  • 增强代码灵活性: 父类引用可以指向不同的子类对象,能够适应需求的变化。

  • 支持接口和抽象类的实现: 多态性使得面向接口编程更加简单。

问题

  1. 什么是类?类在 Java 中有什么作用?
    • 类在Java中是最基础的组件。类可以将一系列属性和方法综合起来,用于表示某一个东西。一个类可以被理解为一个对象的抽象,在创建对象时,需要使用类来创建实例。
  2. 解释 Java 中对象的创建过程,包括内存分配情况。
    • 在Java中,创建对象前需要先用类加载器加载对象对应的类。流程如下:
      • JVM会在首次使用一个类时加载它,JVM会加载类的字节码(.class)文件到内存中。
      • 从磁盘或者网络等位置读取类的字节码文件,并将其转换为 JVM 内部可以处理的二进制数据结构,存放在方法区(在 Java 8 及以后,方法区的实现是元空间,位于本地内存)。
      • 检查字节码文件的格式是否符合 Java 虚拟机规范,确保类文件的正确性,例如检查字节码是否被篡改等。
      • 为类的静态变量分配内存并设置默认初始值。
      • 将类、接口、字段和方法的符号引用转换为直接引用。简单来说,就是确定类中引用的其他类、方法等的实际内存地址。
      • 执行类的初始化代码,主要是执行静态初始化块和对静态变量进行显式赋值。这个阶段是严格按照类中定义的顺序执行的。
    • 创建对象:
      • 默认初始化:分配完内存后,JVM 会对对象的成员变量进行默认初始化。例如,对于基本数据类型,int类型会被初始化为 0,boolean类型会被初始化为false,引用类型会被初始化为null
      • 显式初始化:接着会按照类中定义的变量初始化顺序,对成员变量进行显式初始化。例如,如果在Person类中有private int age = 20;,那么age会被初始化为 20。
      • 构造方法调用:最后会调用对象的构造方法。构造方法可以对对象进行更复杂的初始化操作,例如,在Person类的构造方法中可以初始化其他成员变量或者执行一些其他的逻辑操作。
  3. 简述 Java 中构造函数的特点和用途,它与普通方法有何区别?
    • 构造函数在创建对象实例时调用,通常用于初始化对象的属性,或者执行一些创建对象时所需的流程。
    • 与普通方法的区别:
      1. 代码中不需要定义返回类型,且没有返回值
      2. 无法被重写,但可以被重构
      3. 构造函数名必须与类名完全一致
      4. 生成类对象时,自动被调用
  4. 继承在 Java 中有什么意义?请举例说明如何实现类的继承以及继承带来的好处和潜在风险。
    • 继承可以让一个类(子类)从另一个类(父类)中获取属性和方法,并可以灵活地重写与进行扩展,符合面向对象的编程思想。
    • 好处:代码复用,符合直觉,可灵活拓展
    • 潜在风险:与父类或子类高度耦合;Java仅支持单继承;继承程度过深也许会导致代码维护难度大幅度提高。
  5. 什么是多态?在 Java 中如何通过方法重写和方法重载来体现多态性?
    • 多态即方法可以被重载或重写,以让同一个方法在不同对象中具有不同的行为。重载即同名方法在使用不同类型和长度的参数时有着不同的行为。而重写则是在类中覆盖父类或接口方法来让类的行为变得不同。
  6. 接口在 Java 中的作用是什么?它与抽象类有哪些异同点?
    • 接口在Java中可以让类具备某种功能或特性但并非继承关系。与抽象类不同的是接口可以多继承,但抽象类不能。因为抽象类主张的还是类与类之间的关系,强调代码复用。
  7. 如何在 Java 中实现封装?封装的好处有哪些?
    • Java中,可以将一个类考虑成一个封装的实现,因为封装的本意就是将多个数据和方法集合到一起,并且规定他们对外的可见度。
    • 封装的好处:提高安全性;方便管理;减少耦合
  8. 谈谈你对 Java 中访问修饰符(public、private、protected、default)的理解,它们分别在什么场景下使用?
    • public: 用public修饰的属性和方法对外是公开的,外部对象可以随时访问这些属性和方法并且进行修改和调用。
    • private:用private修饰的属性和方法不对外公开,是内部私有的,只有对象本身可以对其进行直接访问和修改。
    • protected:用protect修饰的属性和方法只对自己和子对象公开,其余对象无法访问和修改。
    • default:在Java中,没有用任何修饰符修饰的属性或方法便为default。具有default访问权限的内容对同一个保重的其他类和对象是可见的。从Java 8开始,default被用来修饰接口中的方法,旨在为接口中的方法定义默认行为,这样即可在不修改实现类的情况下直接添加新功能。
  9. 静态成员(静态变量和静态方法)在 Java 中有什么特性?它们与实例成员有何不同?
    • 静态成员与实例成员的不同就在于,静态成员属于类,而实例成员属于实例对象。静态成员在进行类加载的时候便会为其分配内存,而实例成员则需要在创建一个对象时才会对齐进行初始化和分配内存。

引用


Java学习 - 面向对象
http://example.com/2024/11/26/Java学习/Java学习 - 面向对象/
作者
Clain Chen
发布于
2024年11月26日
许可协议