通常认为面向对象的特征包括:封装、继承与多态三大特征,也有将抽象纳入其中的。
本小节基于前面的介绍,就以这四种特征总结 Java 中是如何体现这些特征的。
22.1 封装
在面向对象编程(OOP)中,封装(Encapsulation) 指的是将对象的数据(属性) 和操作数据的方法捆绑在一起,形成一个独立的单元(即 “类”),并通过控制访问权限来隐藏对象内部的实现细节,只对外暴露必要的接口(方法)供外部交互。
简单来说,封装的核心思想是 “隐藏内部细节,暴露必要接口”,就像一个 “黑盒子”:外部只能通过预设的接口与它交互,而无需知道内部如何运作。
封装的主要目的:
- 数据保护:防止外部代码随意修改对象内部的数据,避免数据被意外破坏或篡改。
- 简化使用:外部只需关注 “如何使用对象”(调用哪些方法),无需了解 “对象内部如何实现”,降低了代码的耦合度。
- 代码维护性:内部实现细节的修改不会影响外部使用,便于后续迭代和维护。
Java中的实现方式:
在 Java 中封装通过访问控制修饰符来控制类成员(属性和方法)的可见性,访问级别从大到小依次包括:
-
公有(public):类内外均可访问,通常作为对外接口。
-
保护(protected):类内部和子类可访问(介于私有和公有之间)。
-
**包内私有:**类内部与本包中的类可访问
-
私有(private):仅类内部可访问,外部无法直接访问。
对于属性私有,我举一个反例,比如下面的类将所有的属性设置为public,这样在类外的任何位置都可以跟简单的使用丢点运算符进行访问:
/**
* @author 老谭
*/
public class Dog {
public int age; // 年龄
public float weight; // 体重
public String breed; // 品种
public String color; // 毛色
}
下面的代码演示了使用Dog类:
Dog erHa1 = new Dog();
erHa1.age = -1;
erHa1.weight = -2.5F;
erHa1.breed = null;
erHa1.color = null;
可以看到其中的属性值可以被设置的不合理,但是对应代码来说,没有办法阻止使用该类的开发人元这么做。
如果我们将属性进行私有化,且提供public的setter方法,则情况有所不同:
/**
* @author 老谭
*/
public class Dog {
private int age; // 年龄
private float weight; // 体重
private String breed; // 品种
private String color; // 毛色
public int getAge() {
return age;
}
public void setAge(int age) {
if (age <= 0) {
// 可以抛出异常
} else {
this.age = age;
}
}
public float getWeight() {
return weight;
}
public void setWeight(float weight) {
if (weight <= 0) {
// 可以抛出异常
} else {
this.weight = weight;
}
}
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
if (breed == null) {
// 可以抛出异常
} else {
this.breed = breed;
}
}
public String getColor() {
return color;
}
public void setColor(String color) {
if (color == null) {
// 可以抛出异常
} else {
this.color = color;
}
}
如果此时再访问属性,则只能使用setter与getter方法了,且对应setter方法而言,由于对参数进行了有效性校验,一些明显不合理的数据就不能复制给属性了。
Dog erHa1 = new Dog();
erHa1.setAge(-1);
erHa1.setWeight(-2.5F);
erHa1.setBreed(null);
erHa1.setColor("灰色");
上面的setter调用中,只有color属性可以正常赋值,其他都不能成功。
一句话总结就是:封装就像给对象穿上了一层 “保护壳”,确保内部数据的安全性和完整性,同时简化了外部的使用方式。它是实现代码模块化、提高可维护性的重要手段。
22.2 继承
在面向对象编程(OOP)中,继承(Inheritance) 指的是一个类(称为子类或 派生类)可以继承另一个类(称为 父类、 基类或超类)的属性和方法,并可以在此基础上添加新的属性 / 方法或重写父类的方法,从而实现代码的复用和扩展。
简单来说,继承的核心思想是 “基于已有类创建新类”,就像现实世界中 “子承父业” 的概念 — 子类可以继承父类的 “资产”(属性和方法),同时还能发展自己的 “特色”。
继承的主要目的:
- 代码复用:避免重复编写相同的代码,子类可以直接使用父类已有的功能。
- 功能扩展:在父类基础上添加新的属性或方法,使子类具备更具体的功能。
- 层次化设计:通过继承构建类之间的层次关系(如 “狗–>杂食性动物–>动物”),使代码结构更清晰。
Java中的实现方式:使用 extends 关键字
Java 中继承的关键概念包括:
- 单继承:一个子类只能继承一个父类,Object是所有类的最顶层父类。
- 方法重写(Override):子类可以定义与父类同名的方法,覆盖父类的实现,实现个性化功能。
- super( ):在子类中通过super( )调用父类的方法。
一句话总结:继承通过 “复用已有代码 + 扩展新功能” 的方式,提高了代码的可维护性和扩展性,是构建复杂类层次结构的重要手段。它让我们可以基于通用类创建更具体的类,体现了 “从一般到特殊” 的抽象思维。
22.3 多态
多态(Polymorphism)是指的是同一行为(方法调用)在不同对象上会产生不同的表现形式。简单来说,就是 “一个接口,多种实现”。
多态的核心思想是:通过父类引用指向子类对象,当调用方法时,实际执行的是子类重写后的方法,而非父类的方法。这种特性让代码更灵活、更具扩展性。
多态的实现条件:
- 继承关系:必须存在父类与子类的继承关系(包括接口实现,因为接口可以看作特殊的父类)。
- 方法重写(Override):子类需要重写父类中的方法(接口的实现类需要实现接口中的抽象方法)。
- 父类引用指向子类对象:通过父类类型的变量来引用子类的实例。
多态的作用:
- 代码灵活性:无需修改调用逻辑,只需更换子类对象,即可实现不同功能。
- 简化代码:通过统一的父类接口操作不同子类,减少重复代码。
- 可扩展性:新增子类时,无需修改原有代码(符合 “开闭原则”)。例如,在之前的例子中(转型),有个父类Shape,有3个子类:Square(正方形),Rectangle(长方形);此时要新增三角形 Triangle 类并重写 getArea( ) 方法,直接用 Shape triangle = new Triangle( 4,10); 的形式创建实例,然后作为实参传给调用ShapeOpr 类的compareTo方法,根本就不用修改 compareTo 方法。Triangle类的声明如下:
/**
* @author 老谭
*/
public class Triangle extends Shape {
private double height;
private double width;
public Triangle(double height, double width) {
this.height = height;
this.width = width;
}
@Override
public double getArea() {
return height * width / 2;
}
}
多态的常见形式:
- 方法重写:上述示例中通过继承和重写实现,属于运行时多态(程序运行时才确定具体调用哪个子类的方法)。
- 方法重载:同一个类中,方法名相同但参数列表(数量、数据类型、顺序)不同,属于编译时多态(编译时确定调用哪个方法)。
一句话总结就是:多态是 Java 中实现代码灵活复用和扩展的重要机制,它允许通过统一的接口操作不同的实现,让程序更易于维护和扩展,是面向对象设计中 “抽象” 思想的具体体现。
22.4 抽象
在面向对象编程(OOP)中,抽象(Abstraction) 是一种核心思想和设计原则,它指的是忽略次要细节,只关注本质特征,即从具体事物中提炼出共同的、本质的属性和行为,形成抽象的概念(如类或接口),而隐藏其具体实现细节。
简单来说,抽象的核心是 “关注是什么,而非怎么做”— 它帮助我们抓住问题的核心,忽略无关紧要的细节,从而简化复杂系统的设计。
抽象的主要目的:
- 简化复杂度:将复杂的现实世界问题分解为可管理的抽象概念,降低理解和设计难度。
- 聚焦核心特征:只保留与当前问题相关的属性和行为,过滤掉无关细节。
- 统一接口:通过抽象定义通用的操作方式,使不同的具体实现可以通过统一的接口交互。
在 Java 中,抽象主要通过两种方式实现:
- **抽象类(Abstract Class)**包含抽象方法(只有声明、没有实现)的类,不能被实例化,只能作为父类被继承。子类必须实现父类中的所有抽象方法。
- **接口(Interface)**完全抽象的结构,只定义方法的声明(在 Java 8 + 中可以有默认方法,静态方法),不包含任何实现。类通过 “实现” 接口来遵循其定义的规范。、
抽象与其他 OOP 特性的关系:
- 抽象是封装的基础:封装隐藏的是实现细节,而抽象定义的是 “应该有什么”。
- 抽象是继承和多态的前提:继承基于抽象的 “父类 - 子类” 层次,多态则通过抽象接口实现不同具体行为的统一调用。
一句话总结:抽象是 OOP 的 “灵魂” 之一,它帮助我们从具体事物中提炼共性、简化设计,并为代码的复用和扩展奠定基础。就像设计图纸只规定建筑的结构和功能,而不关心具体用什么砖一样,抽象定义了 “做什么”,而把 “怎么做” 留给具体实现。
22.5 小结
Java面向对象编程的四大核心特征包括:封装、继承、多态和抽象。封装通过访问控制修饰符隐藏内部实现,仅暴露必要接口;继承允许子类复用和扩展父类功能;多态实现同一方法在不同对象上的差异化表现;抽象则通过抽象类和接口提取共性特征,隐藏实现细节。这些特征共同构建了Java面向对象的基础框架,提高了代码的复用性、扩展性和维护性。通过合理运用这些特性,可以设计出更加灵活、高效的软件系统。

被折叠的 条评论
为什么被折叠?



