什么是面对对象?
OOP 表示面向对象编程(Object-Oriented Programming)。
面向对象是指软件工程中的一类编程风格。除了面向对象外还有面向过程、指令式编程、函数编程等。
常拿来和面向对象比较的是面向过程。
- 面向过程(Procedure Oriented)
是一种以过程为中心的编程思想,是自顶而下的编程模式。最典型的面向过程的编程语言是C语言。在面向过程语言中,需要把问题拆解成一个个步骤,每个步骤写成一个函数,然后以此调用它。面向过程进行的软件开发,其代码都是流程化的,很明确知道第一步做什么,第二步做什么,代码执行效率很高。但是也存在着代码重复利用率低,扩展能力差,后期维护成本高等问题。
- 面向对象(Object Oriented)
面向对象程序设计在某种程度上通过强调可重复性解决了这一问题。目前较为流行的面向对象语言主要有Java、C#、C++、Python、Ruby、PHP等。简单来说,面向对象的开发范式中,程序员将问题分解成一个一个步骤,对每个步骤进行相应的抽象,形成对象,通过不同对象之间的调用,组合解决问题。就是说,在进行面向对象进行编程的时候,要把属性、行为等封装成对象,然后基于这些对象及对象的能力进行业务逻辑的实现。比如:想要造一辆车,上来要先把车的各种属性定义出来,然后抽象成一个Car类。
面向对象编程与过程编程相比有几个优点:
- OOP 更快更容易执行
- OOP 为程序提供了清晰的结构
- OOP 有助于保持 Java 代码干燥( DRY,"Don't Repeat Yourself"),并使代码更易于维护、修改和调试
- OOP 使得用更少的代码和更短的开发时间创建完全可重用的应用程序成为可能
提示:DRY 原则旨在减少代码的重复。您应该提取应用程序中通用的代码,然后将它们放在某处并重复使用它们。
类的定义
在 Java 中,类(Class)是面向对象编程的核心概念,它是对现实世界中某一类事物的抽象描述,包含了这类事物的属性(数据)和行为(方法)。可以将类理解为一个模板或蓝图,而对象则是根据这个模板创建的具体实例。
类和对象的关系举例:
类 | 对象 |
---|---|
水果 | 苹果、香蕉、芒果 |
汽车 | 沃尔沃、奥迪、保时捷 |
所以,类是对象的模板,对象是类的实例。
创建单个对象时,它们会从类中继承所有变量和方法。
类的基本结构
一个完整的 Java 类通常包含以下几个部分:
- 类的声明:定义类的名称、访问修饰符等
- 属性(成员变量):描述类的特征或状态
- 构造方法:用于初始化对象
- 成员方法:描述类的行为或功能
- 内部类(可选):在类内部定义的类
- 静态成员(可选):属于类本身的属性和方法
类的定义语法
java
[修饰符] class 类名 [extends 父类名] [implements 接口名列表] {
// 属性定义
[修饰符] 数据类型 属性名1;
[修饰符] 数据类型 属性名2 = 初始值;
// 构造方法
[修饰符] 类名([参数列表]) {
// 初始化代码
}
// 成员方法
[修饰符] 返回值类型 方法名([参数列表]) {
// 方法体
[return 返回值;]
}
// 其他成员...
}
各部分说明
- 修饰符:
- 访问修饰符:
public
、protected
、默认(不写)、private
- 其他修饰符:
abstract
、final
、static
(内部类)等
访问修饰符访问控制权限:
修饰符 | 同一类中 | 同一包中 | 不同包的子类中 | 不同包的非子类中 |
---|---|---|---|---|
public |
✅ | ✅ | ✅ | ✅ |
protected |
✅ | ✅ | ✅ | ❌ |
默认(不写) | ✅ | ✅ | ❌ | ❌ |
private |
✅ | ❌ | ❌ | ❌ |
- 类名:
- 遵循驼峰命名法,首字母大写(如
Student
、UserAccount
) - 通常使用名词,代表一类事物
- 属性(成员变量):
- 定义类的状态信息
- 可以指定初始值,也可以不指定(有默认值)
- 例如:
String name
;int age = 18
;
- 构造方法:
- 方法名与类名完全相同
- 没有返回值类型(包括
void
) - 用于创建对象时初始化属性
- 如果没有显式定义,
Java
会提供一个默认的无参构造方法
- 成员方法:
- 描述类的行为
- 有返回值类型(无返回值用
void
) - 可以有参数列表,也可以没有
示例:定义一个汽车类
java
// 公共类,类名与文件名相同
public class Car {
// 属性(成员变量)
private String brand; // 品牌
private String color; // 颜色
private int speed; // 速度
// 无参构造方法
public Car() {
// 默认初始化
this.speed = 0;
}
// 有参构造方法
public Car(String brand, String color) {
this.brand = brand;
this.color = color;
this.speed = 0;
}
// 成员方法:加速
public void accelerate(int increment) {
if (increment > 0) {
this.speed += increment;
System.out.println(brand + "加速了,当前速度:" + speed + "km/h");
}
}
// 成员方法:刹车
public void brake() {
this.speed = 0;
System.out.println(brand + "刹车了,当前速度:0km/h");
}
// 成员方法:获取当前速度
public int getSpeed() {
return this.speed;
}
}
构造方法
在 Java 中,构造方法(Constructor)是一种特殊的方法,用于在创建对象时初始化对象的属性。它在对象被`new`关键字实例化时自动调用,是类定义中非常重要的组成部分。
构造方法的基本特点
- 方法名与类名完全相同(包括大小写)
- 没有返回值类型(甚至不能写
void
) - 不能被
static
、final
、abstract
等修饰符修饰 - 当使用
new
关键字创建对象时自动调用
默认构造器(无参构造方法)
如果一个类中没有显式定义任何构造方法,Java 编译器会自动生成一个默认的无参构造方法。
特点:
- 没有参数
- 方法体为空
- 访问修饰符与类的访问修饰符一致
示例:
java
public class Person {
String name;
int age;
// 没有显式定义构造方法,编译器会生成默认无参构造器
}
// 使用默认构造器创建对象
public class Test {
public static void main(String[] args) {
Person p = new Person(); // 调用默认无参构造器
}
}
注意:如果显式定义了任何构造方法,Java 将不再生成默认构造器。
自定义构造器
开发者可以根据需求自定义构造方法,用于在创建对象时直接初始化属性。
示例:带参数的构造器
java
public class Person {
String name;
int age;
// 自定义有参构造器
public Person(String name, int age) {
this.name = name; // this表示当前对象
this.age = age;
}
public void introduce() {
System.out.println("我叫" + name + ",今年" + age + "岁");
}
public static void main(String[] args) {
// 使用自定义构造器创建对象
Person p = new Person("张三", 20);
p.introduce(); // 输出:我叫张三,今年20岁
}
}
作用:
- 简化对象初始化过程
- 可以在构造器中添加验证逻辑,保证数据合法性
构造器重载(Constructor Overloading)
在一个类中,可以定义多个构造方法,只要它们的参数列表不同(参数个数、类型或顺序不同),这就是构造器重载。
java
public class Student {
private String name;
private int age;
private String major;
// 1. 无参构造器
public Student() {
// 可以设置默认值
this.name = "未知";
this.age = 0;
this.major = "未知";
}
// 2. 带一个参数的构造器
public Student(String name) {
this.name = name;
this.age = 0;
this.major = "未知";
}
// 3. 带两个参数的构造器
public Student(String name, int age) {
this.name = name;
this.age = age;
this.major = "未知";
}
// 4. 带三个参数的构造器
public Student(String name, int age, String major) {
this.name = name;
this.age = age;
this.major = major;
}
// 打印学生信息
public void showInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",专业:" + major);
}
public static void main(String[] args) {
// 调用不同的构造器创建对象
Student s1 = new Student();
Student s2 = new Student("李四");
Student s3 = new Student("王五", 21);
Student s4 = new Student("赵六", 22, "计算机科学");
s1.showInfo(); // 姓名:未知,年龄:0,专业:未知
s2.showInfo(); // 姓名:李四,年龄:0,专业:未知
s3.showInfo(); // 姓名:王五,年龄:21,专业:未知
s4.showInfo(); // 姓名:赵六,年龄:22,专业:计算机科学
}
}
构造器之间的调用(this()关键字)
在一个构造器中,可以通过this
(参数)调用同一个类中的其他构造器,从而减少代码冗余。
规则:
this
(参数)必须放在构造器的第一行- 不能在两个构造器中互相调用(避免无限循环)
示例:
java
public class Car {
private String brand;
private String color;
private int price;
// 无参构造器
public Car() {
this("未知品牌", "白色"); // 调用两个参数的构造器
}
// 两个参数的构造器
public Car(String brand, String color) {
this(brand, color, 0); // 调用三个参数的构造器
}
// 三个参数的构造器
public Car(String brand, String color, int price) {
this.brand = brand;
this.color = color;
this.price = price;
}
}
this 关键字的用法
在 Java 中,this
是一个特殊的关键字,它代表当前对象的引用(即当前正在操作的对象本身)。this
主要用于解决变量名冲突、调用类的其他构造方法以及传递当前对象等场景。
this的核心作用
this
始终指向当前对象 ------ 即正在执行方法的那个对象,或者正在被构造的对象。
this的常见用法
- 区分成员变量和局部变量(解决命名冲突)
当方法的参数名或局部变量名与类的成员变量名相同时,使用this
来明确指定成员变量。
示例:
java
public class Person {
private String name; // 成员变量
private int age; // 成员变量
// 构造方法中参数名与成员变量名相同
public Person(String name, int age) {
this.name = name; // this.name 指成员变量,name 指参数
this.age = age; // this.age 指成员变量,age 指参数
}
// 普通方法中局部变量与成员变量名相同
public void setName(String name) {
this.name = name; // 明确使用成员变量
}
}
- 调用类中的其他构造方法(
this
(参数))
在一个构造方法中,可以通过this
(参数)调用同一个类中的其他构造方法,避免代码重复。
规则:
this
(参数)必须放在构造方法的第一行- 不能在两个构造方法中互相调用(会导致无限循环)
示例:
java
public class Student {
private String name;
private int age;
private String major;
// 无参构造器
public Student() {
this("未知", 0); // 调用两个参数的构造器
}
// 两个参数的构造器
public Student(String name, int age) {
this(name, age, "未知专业"); // 调用三个参数的构造器
}
// 三个参数的构造器(最终实现初始化)
public Student(String name, int age, String major) {
this.name = name;
this.age = age;
this.major = major;
}
}
- 调用类中的成员方法(
this.方法名()
)
可以通过this
调用当前对象的其他成员方法,增强代码可读性(通常可省略this
)。
示例:
java
public class Calculator {
private int result;
public void add(int num) {
result += num;
}
public void addTwice(int num) {
this.add(num); // 调用当前对象的add()方法
this.add(num); // 等价于直接写 add(num)
}
}
- 作为方法的返回值(返回当前对象)
在方法中使用return this
可以返回当前对象,便于实现方法链编程(连续调用多个方法)。
示例:
java
public class Builder {
private String name;
private int age;
// 设置name并返回当前对象
public Builder setName(String name) {
this.name = name;
return this; // 返回当前对象
}
// 设置age并返回当前对象
public Builder setAge(int age) {
this.age = age;
return this; // 返回当前对象
}
public static void main(String[] args) {
// 方法链编程:连续调用多个方法
Builder builder = new Builder()
.setName("张三")
.setAge(20);
}
}
- 作为参数传递给其他方法
将当前对象作为参数传递给其他方法,便于在外部操作当前对象。
示例:
java
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
// 将当前对象传递给其他方法
public void introduce() {
Greeting.sayHello(this); // this代表当前Person对象
}
public String getName() {
return name;
}
}
class Greeting {
// 接收Person对象作为参数
public static void sayHello(Person p) {
System.out.println("你好,我是" + p.getName());
}
}
this的注意事项
this
只能在非静态方法或构造方法中使用,不能在static
方法中使用(因为static
方法属于类,不依赖对象)。this
不能用于引用类的静态成员(静态成员属于类,应使用类名访问)。this
不能为null
,它始终指向一个具体的对象。
总结
this
关键字的核心是代表当前对象,主要用法包括:
- 区分成员变量和局部变量。
- 调用同类中的其他构造方法。
- 调用当前对象的成员方法。
- 作为返回值返回当前对象。
- 作为参数传递给其他方法。