面向对象编程(Object-Oriented Programming,简称OOP)和面向过程编程(Procedure-Oriented Programming)是两种不同的编程范式,它们在设计和实现软件时采用了不同的方法和哲学。
一、面向对象编程
-
核心概念:面向对象编程的核心是"对象",对象可以包含数据(属性)和代码(方法)。万物皆对象。
-
封装:将数据和操作数据的方法组合在一起,隐藏内部实现细节。
-
继承:允许新创建的类(子类)继承现有类(父类)的属性和方法。
-
多态:允许不同类的对象对同一消息做出响应,但具体的行为会根据对象的实际类型而有所不同。
-
应用:面向对象编程适用于大型、复杂的系统,可以提高代码的复用性和可维护性。
优点:可维护性,可复用性,可扩展性,灵活性好。
二、面向过程编程
- 核心概念:面向过程编程侧重于将问题分解成一系列的过程或函数。
- 过程:每个过程执行特定的任务,并且可以调用其他过程。
- 数据和函数分离:数据和处理数据的函数是分开的,函数操作数据但不包含数据。
- 优点:简单、直观,适合小型或逻辑简单的程序。
- 缺点:难以维护,无法复用,难以扩展,灵活性差。
三、对比
- 设计哲学:面向对象强调的是数据和功能的结合,面向过程则强调的是功能的分解。
- 代码组织:面向对象通常以类和对象的形式组织代码,面向过程则以函数和过程的形式组织。
- 可维护性:面向对象由于其封装、继承和多态的特性,通常更容易维护和扩展。
- 适用场景:面向对象适合于需要高度模块化和可复用性的复杂系统,而面向过程适合于逻辑简单、规模较小的程序。
一、什么是类
类(Class)
- 定义:类是现实世界中某些具有共同属性(数据)和方法(行为)的对象的抽象和模板。类是封装对象的属性和行为的载体。
- 属性:类中的属性代表了对象的状态信息,通常是变量。
- 方法:类中的方法定义了对象的行为,通常是函数。
- 封装:类通过将数据和操作数据的方法封装在一起,保护了数据不被外部直接访问,只能通过类提供的方法进行操作。
- 创建:通过类可以创建多个对象实例,每个实例拥有自己的状态,但共享相同的行为定义
二、什么是对象
- 实例:对象是类的实例化,每个对象都是一个独立的实体,拥有自己的属性值。
- 状态:对象的状态由其属性值决定,不同的对象可以有不同的状态。
- 行为:对象的行为由类中定义的方法决定,所有对象实例共享相同的方法。
- 交互:对象之间可以通过消息传递进行交互,一个对象可以请求另一个对象执行其方法。
- 作用:对象是程序中的基本单位,用于存储数据和执行操作。
类与对象的关系
- 模板与实例:类是创建对象的模板,对象是类的实例。就像模具和铸造出来的产品一样。
- 属性与状态:类的属性定义了对象可能拥有的状态,而对象的属性值则代表了其当前状态。
- 方法与行为:类的方法定义了对象的行为,对象通过调用这些方法来执行操作。
- 多态性:对象可以通过继承和接口实现多态性,即不同的对象可以对相同的消息做出响应,但具体的行为会根据对象的实际类型而有所不同。
三、成员变量
属性(成员变量)=访问修饰符+数据类型+变量名
Java中,对象的属性也称为成员变量,成员变量可以是任意类型,成员变量的作用域是整个类。
public calss Book{ //定义一个书类
private String name; //定义String类型的成员变量
public String getName(){ //成员变量name的get方法
return name;
}
public void setName(String name){ //成员变量name的set方法
this.name = name; //将参数值赋给成员变量name
}
}
上面创建的是一个Book类,在类中设置了一个name属性,并编写了该属性的Getter/Setter方法。
在Java语言中定义类需要使用class关键字,Book是类的名称,在Book类中定义了一个成员变量,成员变量的类型为String类型。成员变量其实就是一个普通的变量,可以为它设置初始值,也可以不设置初始值,如果不设置初始值,那么会有默认的初始值。
四、成员方法
在Java中,使用成员方法对应于类对象的行为,以上面的Book类为例,它包含了getName()和setName()两个方法,这两个成员方法分别为获取图书名称和设置图书名称的方法。
定义成员方法的语法格式如下:
权限修饰符 返回值类型 方法名(参数类型 参数名){
…… //方法体
return 返回值;
}
一个成员方法可以有参数,这个参数可以是对象,也可以是基本数据类型的变量,同时成员方法有返回值和不返回任何值的选择,如果方法需要返回值,可以使用return关键字来返回值,使用这个关键字,方法执行到这句语句的时候,方法将被中止。(如果想要使成员方法无返回值,可以使用void关键字表示)。
成员方法的返回值可以是计算结果,也可以是其它想要的数值和对象,返回值的类型要与方法返回值类型一致。
在成员方法中可以调用其他成员方法和类成员变量,在成员方法中也可以定义一个变量,但是方法中定义的变量为局部变量。
成员方法和成员变量统称为类成员。
五、对象实例化(构造器)
对象实例化是一个过程,它创建了类的一个具体实例,即对象。不同的编程语言有不同的语法来实现对象的实例化。构造器是类中用于实例化Java对象的一个特殊方法,该方法要求方法名必须与类名相同
1.默认构造器(无参)
当一个类没有构造器,就默认为无参构造器。当有构造器时,无参构造器需手写。
public 类名(){}
默认构造器不接收任何参数,会调用父类的无参构造器(如果存在的话),然后初始化类的对象。
public class MyClass {
private String name;
// 没有显式定义构造器,编译器将提供一个无参构造器
}
// 实例化对象,使用默认的无参构造器
MyClass myObject = new MyClass();
MyClass有一个私有的name属性,但没有定义任何构造器。当你创建MyClass的实例时,使用的是默认的无参构造器。
2.有参构造器
有参构造器(Parameterized Constructor)是一种接收初始化参数的构造方法。当你创建对象时,可以传递参数给这些构造器,以便在对象创建时就初始化对象的状态。
以下是一些关于有参构造器的关键点:
- 定义:有参构造器的方法名必须与类名完全相同,并且不返回任何值(不包括
void
)。 - 参数:构造器可以有一个或多个参数,用于接收初始化数据。
- 作用:主要用于在创建对象时设置对象的初始状态。
- 调用:在创建对象时,必须提供与构造器参数匹配的参数值。
下面是一个Java类使用有参构造器的例子:
public class Person {
private String name;
private int age;
// 有参构造器,接收两个参数:姓名和年龄
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 其他方法,例如获取姓名和年龄
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
// 使用有参构造器实例化对象
Person person = new Person("Alice", 30);
包含无参构造器和有参构造器:
public class Person {
private String name;
private int age;
// 无参构造器
public Person() {
this("Unknown", 0); // 调用有参构造器,设置默认值
}
// 有参构造器,接收两个参数
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// 使用无参构造器实例化对象,实际上会调用有参构造器
Person personDefault = new Person();
在这个例子中,无参构造器通过this("Unknown", 0);
调用了有参构造器,从而实现了构造器之间的调用。这是一种常见的模式,用于为类的不同构造器提供一致的初始化逻辑。
3.构造器重载
构造器重载(Constructor Overloading)是Java中多态的一种表现,允许一个类拥有多个同名的构造器,只要它们的参数列表不同即可。这使得类能够提供多种方式来创建对象,每种方式都可以接受不同数量或类型的参数。
构造器重载的要点:
- 方法名相同:所有重载的构造器必须具有相同的方法名,即类名。
- 参数列表不同:构造器的参数数量或类型(或两者)必须不同。
- 返回类型:构造器没有返回类型,即使是
void
也不行。 - 访问修饰符:可以有不同的访问修饰符,但这不影响重载。
public class Car {
private String model;
private String color;
private int year;
// 无参构造器
public Car() {
this("Unknown", "Black", 0); // 默认构造器,调用有参构造器
}
// 有参构造器1:接收三个参数
public Car(String model, String color, int year) {
this.model = model;
this.color = color;
this.year = year;
}
// 有参构造器2:接收两个参数
public Car(String model, int year) {
this(model, "Black", year); // 调用另一个有参构造器
}
// 有参构造器3:接收一个参数
public Car(String model) {
this(model, "Black", 0); // 调用另一个有参构造器
}
// 其他方法...
}
// 使用不同的构造器实例化对象
Car car1 = new Car(); // 使用无参构造器
Car car2 = new Car("Tesla", "Red", 2021); // 使用有参构造器1
Car car3 = new Car("Toyota", 2020); // 使用有参构造器2
Car car4 = new Car("Honda"); // 使用有参构造器3
六、对象的使用
在面向对象编程(OOP)中,对象的使用通常涉及以下几个步骤:
- 定义类:首先,你需要定义一个类(Class),它是一个蓝图,描述了具有相同属性和方法的对象的结构。
- 实例化对象:使用类来创建一个或多个对象实例。这通常通过调用类的构造器完成。
- 访问属性:对象的属性(也称为字段或成员变量)可以通过点(
.
)操作符来访问和修改。 - 调用方法:对象的方法(也称为成员函数)可以通过点操作符调用,以执行某些操作或返回某些值。
- 修改对象状态:通过设置对象的属性,可以改变对象的状态。
- 实现接口或继承:对象可能实现了特定的接口或继承自其他类,这为它们提供了额外的行为或属性。
- 销毁对象:在某些语言中,如Java,对象会在不再被引用时由垃圾收集器自动销毁。在其他语言中,如C++,可能需要手动管理内存和对象的销毁。
// 定义一个类
class Person {
private String name;
private int age;
// 构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 获取姓名的方法
public String getName() {
return name;
}
// 设置姓名的方法
public void setName(String name) {
this.name = name;
}
// 获取年龄的方法
public int getAge() {
return age;
}
// 描述个人信息的方法
public void describe() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
// 使用类创建对象
public class Main {
public static void main(String[] args) {
// 实例化Person类的对象
Person person1 = new Person("Alice", 30);
// 访问和修改属性
person1.setName("Bob");
person1.setAge(25);
// 调用方法
person1.describe(); // 输出: Name: Bob, Age: 25
// 创建另一个对象
Person person2 = new Person("Charlie", 40);
person2.describe(); // 输出: Name: Charlie, Age: 40
}
}
七、对象的销毁(GC垃圾回收)
在Java中,对象的销毁是由垃圾收集器(Garbage Collector, GC)自动管理的。当一个对象没有任何引用指向它时,它就变得“无用”,GC会在某个时间点回收它所占用的内存。 System.GC()
- 垃圾收集触发条件:当对象没有被任何变量、对象或类引用时。
- 垃圾收集过程:GC周期性地运行,检查对象的引用状态,并回收那些没有被引用的对象。
- GC可回收new的对象,系统资源对象不能回收
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 30);
// 当person变量离开作用域或被设置为null时,对象可能被GC回收
person = null; // 显式地断开引用,加快对象的回收
}
}
八、匿名对象
匿名对象:没有名字的对象。只用一次。
格式如下:
new Person().showMessage();
这种对象通常用于临时使用,不需要命名的情况。不同的编程语言对匿名对象的支持程度不同。
在Java中,匿名对象通常用于创建一次性使用的对象,或者作为参数传递给方法。例如,创建一个实现了Runnable
接口的匿名对象,并将其作为线程启动:
在Java中,匿名对象通常用于创建一次性使用的对象,或者作为参数传递给方法。例如,创建一个实现了Runnable接口的匿名对象,并将其作为线程启动:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello from an anonymous Runnable!");
}
}).start();
实例化对象方式:
new 对象
Object clone
最高设计原则:高内聚低耦合。
-
继承(Inheritance):父类,子类
- 继承是一种"是一个"(is-a)的关系。例如,如果有一个
Animal
类,可以有一个Dog
类继承自它,因为狗是一种动物。
- 继承是一种"是一个"(is-a)的关系。例如,如果有一个
-
实现(Implementation):订票接口,网上订票类
- 实现通常指的是一个类实现了一个接口。接口定义了一组方法,类必须实现这些方法,但接口本身不提供实现。
-
关联(Association):学生类,老师类
- 关联是一种"有"(has-a)的关系。例如,一个
Car
类可能有一个Engine
类作为其属性,表示汽车有引擎。
- 关联是一种"有"(has-a)的关系。例如,一个
-
聚合(Aggregation):学生类,班级类
- 聚合是一种特殊的关联,表示整体与部分的关系,但部分可以独立于整体存在。例如,一个
University
类可能聚合了多个Student
类的对象。
- 聚合是一种特殊的关联,表示整体与部分的关系,但部分可以独立于整体存在。例如,一个
-
组合(Composition):心脏,人
- 组合也是整体与部分的关系,但与聚合不同,部分不能独立于整体存在。如果整体被销毁,部分也会被销毁。
-
依赖(Dependency):动物,水
- 依赖是一种"使用"(uses-a)的关系。一个类可能在其方法中使用另一个类的对象,但不一定拥有它。