什么是JAVA的面向对象思想?
当我们谈到面向对象思想,就得先讨论一下面向过程思想了。面向过程主要关注于解决“怎么做”的问题,即关注如何一步步实现功能,核心单元是函数(Function) 或 过程(Procedure),数据(变量)和操作数据的函数是分开的,函数处理数据并返回结果。典型特点是:
-
自顶向下设计(Top-Down Design),将复杂问题分解为多个小问题,每个小问题由一个函数解决,例如:计算学生成绩的流程可以分解为: 输入成绩 → 计算总分 → 计算平均分 → 输出结果,每个步骤对应一个函数。
-
数据与函数分离,数据(变量)通常是全局的或通过参数传递给函数,函数只负责处理数据,但不封装数据。
这样做的优点是:
-
简单直接,代码比较通俗易懂,适合小型程序或数学计算(如排序、数值计算)。
-
执行效率高,函数调用比对象方法调用更快,因为无对象创建开销。
-
易于调试:流程清晰,便于跟踪执行顺序。
缺点是:
-
难以维护,随着代码增长,函数和数据的关系变得混乱,数据之间的传递错综复杂。
-
代码复用性低,没有继承和接口实现来复用代码。
-
扩展性差,新增功能可能需要修改多个函数,违反 开闭原则(OCP)(开闭原则:对扩展开放,但对修改关闭)
面向对象编程(OOP)的出现是为了解决 面向过程编程(PP) 在 软件复杂度增长时暴露的局限性。Java 的面向对象(Object-Oriented Programming, OOP)思想是一种以 对象 为核心的编程范式,通过将现实世界的事物抽象为程序中的对象,实现代码的模块化、复用和可维护性。面向对象的三大特性是封装、继承和多态。
封装
核心:隐藏对象的内部细节,仅暴露必要的接口与外部交互
实现方式:
-
使用 private 修饰属性,通过 public 的 getter/setter 方法控制访问。
-
避免直接操作对象内部数据,增强安全性和可维护性。
示例:
public class Person {
private String name; // 私有属性
public String getName() { return name; } // 对外暴露的getter
public void setName(String name) { this.name = name; } // 对外暴露的setter
}
在 Java 中,可以使用Lombok库提供的注解来自动生成getter和setter方法,而无需手动编写这些样板代码,以下是相应的Lombok库下的常用注解:
注解 |
作用 |
---|---|
@Getter |
getXxx() 方法 |
@Setter |
setXxx() 方法 |
@ToString |
toString() |
@EqualsAndHashCode |
equals() + hashCode() |
@Data |
@Getter+@Setter+@ToString+@EqualsAndHashCode |
@NoArgsConstructor |
无参构造方法 |
@AllArgsConstructor |
全参构造方法 |
继承
核心:子类继承父类的属性和方法,实现代码复用和层次化设计。
-
实现方式:
-
使用 extends 关键字继承父类。
-
子类可重写(@Override)父类方法,或通过 super 调用父类逻辑。
-
为了防止C++中的菱形继承的现象,Java中不允许多继承,即一个子类继承多个父类。但是一个类可以实现多个接口。
示例:
class Animal {
void eat() { System.out.println("Eating..."); }
}
class Dog extends Animal { // 继承
@Override
void eat() { System.out.println("Dog eats bones"); }
}
多态
-
核心:同一行为在不同对象中有不同实现方式,分为 编译时多态(方法重载)和 运行时多态(方法重写)。
-
实现方式:
-
方法重载(Overload):同名方法,参数列表不同(参数类型、参数个数或参数顺序不同)。
-
方法重写(Override):子类重写父类方法。
-
通过父类引用指向子类对象(向上转型)实现动态绑定。
多态是指子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。多态这种特性也需要编程语言提供特殊的语法机制来实现,比如继承、接口类,多态可以提高代码的扩展性和复用性。
示例:
class Animal {
void eat() { System.out.println("Eating..."); }
}
class Dog extends Animal { // 继承
@Override
void eat() { System.out.println("Dog eats bones"); }
}
抽象的思想
-
核心:提取共性特征,忽略具体细节,通过抽象类和接口定义规范。
-
实现方式:
-
抽象类(abstract class):可包含抽象方法(无实现)和具体方法。
-
接口(interface):Java 8 后支持默认方法(default)和静态方法,定义行为契约。
示例:
class Animal {
void eat() { System.out.println("Eating..."); }
}
class Dog extends Animal { // 继承
@Override
void eat() { System.out.println("Dog eats bones"); }
}
接口多态示例:
interface Flyable {
void fly();
}
class Bird implements Flyable {
public void fly() {
System.out.println("鸟儿用翅膀飞");
}
}
class Airplane implements Flyable {
public void fly() {
System.out.println("飞机用引擎飞");
}
}
// 多态调用
Flyable flyer = new Bird();
flyer.fly(); // 调用Bird的实现
flyer = new Airplane();
flyer.fly(); // 调用Airplane的实现
抽象类和普通类的区别是什么?
抽象类是 Java 面向对象编程中的重要概念,它介于普通类和接口之间,被abstract关键字修饰,不可被实例化,提供了部分实现的同时又保持了抽象特性。
// 使用 abstract 关键字声明抽象类
public abstract class Animal {
// 普通成员变量
private String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
// 普通方法
public String getName() {
return name;
}
// 抽象方法(没有方法体)
public abstract void makeSound();
// 可以包含具体实现的方法
public void sleep() {
System.out.println(name + "正在睡觉");
}
}
使用abstract关键字修饰的类方法为抽象方法(无需有方法体),有抽象方法的类需要用abstract关键字修饰,成为抽象类。子类在继承抽象类时必须实现子类必须实现所有抽象方法,否则自己也声明为抽象类以实现部分的抽象方法。
抽象类和接口的区别是什么?
-
抽象类用于描述类的共同特性和行为,可以有成员变量、构造方法和具体方法。适用于有明显继承关系的场景,只能单继承。
-
接口用于定义行为规范,可以多实现,只能有常量和抽象方法(Java 8 以后可以有默认方法和静态方法)。适用于定义类的能力或功能。接口不可以有构造方法,在接口里写入构造方法时,编译器提示:Interfaces cannot have constructors,因为接口不会有自己的实例的,自然不需要有构造函数。
抽象类 |
接口 | |
---|---|---|
实现方式 |
extends(只能单继承) |
implements(可以多实现) |
方法 |
可有定义与实现 |
Java 8前只有抽象方法,后支持默认方法 |
访问修饰符 |
成员变量:默认default |
成员变量:public static final |
变量 |
实例变量和静态变量 |
常量(即静态常量) |
设计目的 |
描述类的共同特性(is-a关系) |
定义行为规范(has-a能力) |
总结
维度 |
面向过程(PP) |
面向对象(OOP) |
---|---|---|
核心思想 |
关注“怎么做”(步骤) |
关注“谁来做”(对象交互) |
代码组织 |
函数+数据分离 |
数据和方法封装在对象中 |
复用性 |
函数复用,灵活性低 |
继承/组合/接口,复用性高 |
扩展性 |
修改可能影响全局 |
通过多态和设计模式轻松扩展 |
适用场景 |
简单脚本、数学计算 |
大型系统、GUI、企业级开发 |