头脑风暴:
- 什么是对象?
- 什么是面向对象?
- 为什么要面向对象?
- 面向对象的优缺点?
一切皆对象,现实生活中:电脑、耳机、水杯、书等等,相比现实生活,程序中的对象是抽象出来的,要么是基于现实中的对象抽象出来,只包含了现实中对象的部分信息,要么是根本应用程序的需要而抽象出来的,如:职工对象(通常只记录部分与职工相关性较高的信息),学生对象(通常也只记录与学生相关性较高的信息)。职工和学生是一个“角色对象”,因为他们也可能同时是儿子、女儿、父亲、母亲、观众、演员……,但在特定的场景下仅使用他们对应的属性信息等。程序中也有现实中不存在的对象,比如一个数据库、一张数据表、一个服务器的连接,这是根据应用程序的需要抽象得到的,为了完成业务需求!
面向对象对应的是面向过程。
分析解决某个问题所需要的步骤,然后根据步骤一步一步通过代码实现。
把大象装进冰箱:
- 打开冰箱门;
- 大象进入冰箱;
- 关闭冰箱门。
面向过程,就是按照我们分析好的步骤,按照步骤解决问题。
把事务分解成一个一个对象,然后对象之间分工与合作。
把大象装进冰箱:
- 冰箱门打开(冰箱对象的行为);
- 大象进入冰箱(大象对象的行为);
- 冰箱门关住(冰箱对象的行为)。
面向对象,是以对象功能来划分问题,而不是步骤。
一句话:面向过程数据和操作数据的函数是分离的,按照顺序执行函数,完成任务;面向对象的数据和操作数据的函数被封装在对象内部,是统一的,对象之间通过消息传递进行协作,以完成任务!
面向过程(Procedural Programming)和面向对象(Object-Oriented Programming)是两种编程范式,它们有着不同的思想、设计方式和实现方法。
面向过程思想将程序看作一系列函数或过程的集合,这些函数或过程按照顺序执行,完成特定的任务。在面向过程的程序设计中,数据与行为是分开的,数据和操作数据的函数是分离的。
面向对象思想则认为程序应该是由一组相互作用的对象组成的,每个对象都有自己的状态和行为。面向对象设计中,对象是程序的基本单位,数据和操作数据的函数被封装在对象内部,数据与行为是紧密联系的。
在面向过程编程中,问题被分解为若干个子问题,每个子问题被设计成一个函数,再将这些函数组合起来完成整个任务。程序的设计主要关注如何处理数据,而不是如何组织数据。
在面向对象编程中,问题被抽象成对象,每个对象有自己的属性和方法,对象之间通过消息传递相互协作。程序的设计主要关注如何组织数据,而不是如何处理数据。
在面向过程编程中,数据和函数是分离的,数据的改变需要通过调用函数来实现。常见的面向过程编程语言包括 C、Fortran、Pascal 等。
在面向对象编程中,数据和方法被封装在对象内部,对象之间通过消息传递来实现数据的操作。常见的面向对象编程语言包括 Java、Python、C++、C# 等。
总的来说,面向过程与面向对象各有优缺点,在具体应用中需要根据问题的特点和实际情况选择合适的编程范式。
简单明了:面向过程的编程思想相对简单,易于理解和实现。
我觉得面向过程符合人的常规思想逻辑,我们为了达成目标做事情也是按步骤进行!
效率高:面向过程的编程方式更加接近底层实现,执行效率高。
易于维护:面向过程的程序结构清晰,每个函数完成一个特定的任务,容易进行维护。
技术门槛高:面向对象编程思想较为复杂,需要掌握面向对象的相关概念和技术。
执行效率较低:面向对象的程序实现需要更多的内存空间和处理时间,执行效率相对较低。
我觉得对象里面不是所有的属性和方法都会用到,每次使用要加载整个对象,那么就浪费了资源、降低了效率!
设计复杂度高:面向对象编程需要设计对象的属性和方法,设计复杂度较高,需要花费更多的时间和精力。
主要关注如何组织数据,数据组织的合理性需要站在长远、全局的角度考虑。
在这个例子中,主程序使用了 Scanner 类获取用户输入的两个整数,然后调用 findGcd 函数计算它们的最大公约数。findGcd 函数使用了 for 循环和 if 语句来计算最大公约数。整个程序使用了面向过程的编程方式,将任务分解为一系列的函数,每个函数负责完成特定的功能。函数之间通过参数和返回值进行数据传递和处理。
import java.util.Scanner;public class GcdCalculator {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.print("请输入第一个数:");int num1 = scanner.nextInt();System.out.print("请输入第二个数:");int num2 = scanner.nextInt();int gcd = findGcd(num1, num2);System.out.println("最大公约数是:" + gcd);}public static int findGcd(int num1, int num2) {int smaller = num1 < num2 ? num1 : num2;int gcd = 1;for (int i = 1; i <= smaller; i++) {if (num1 % i == 0 && num2 % i == 0) {gcd = i;}}return gcd;}}
在这个例子中,我们将计算最大公约数的函数findGcd放到了 GcdCalculator 类中,并且在主程序中使用了这个类来创建对象。这个程序使用了面向对象的编程方式,将数据和操作封装在一个类中,使用对象来调用方法,实现了更加直观和灵活的编程方式。这样,当我们需要计算多组数据的最大公约数时,只需要创建多个 GcdCalculator 对象,调用它们的 findGcd 方法即可。
import java.util.Scanner;public class GcdCalculator {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.print("请输入第一个数:");int num1 = scanner.nextInt();System.out.print("请输入第二个数:");int num2 = scanner.nextInt();GcdCalculator calculator = new GcdCalculator();int gcd = calculator.findGcd(num1, num2);System.out.println("最大公约数是:" + gcd);}public int findGcd(int num1, int num2) {int smaller = num1 < num2 ? num1 : num2;int gcd = 1;for (int i = 1; i <= smaller; i++) {if (num1 % i == 0 && num2 % i == 0) {gcd = i;}}return gcd;}}
头脑风暴:
- 什么是封装性?
- 为什么要封装?
- 封装的优缺点?
- 封装的使用场景?
隐藏具体实现 + 访问控制,提高安全性
面向对象的封装性指的是将数据和对数据的操作封装在一个类中,通过类的接口来访问和操作数据,同时将数据的实现细节隐藏在类的内部,不暴露给外部。
封装性是面向对象编程中最基本、最重要的概念之一。它可以有效地保护对象的数据,防止外部的直接访问和修改,从而保证了数据的安全性和完整性。同时,封装性还可以隐藏对象的实现细节,使得对象的使用者不必关心对象的内部实现,只需要关心对象提供的接口即可。
在 Java 中,封装性通常通过访问修饰符(public、protected、private)来实现。将数据成员设置为私有的(private),并提供公有的(public)getter 和 setter 方法,这样就可以实现对数据的访问控制和保护,同时也可以方便地对数据进行操作和修改。这样就实现了类的封装性,同时也提高了代码的可维护性和可重用性。
头脑风暴:
- 什么是继承性?
- 为什么要集成?
- 继承的优缺点?
- 继承的适用场景和不适用场景?
代码复用:继承其他类的属性和方法,增强代码复用!
Java 面向对象编程中的继承性是指,一个类可以从已有的类中继承属性和方法,从而可以扩展已有的类,减少重复代码,提高代码的复用性和可维护性。
在 Java 中,一个类可以通过 extends 关键字继承另一个类的属性和方法。被继承的类称为父类或超类,继承它的类称为子类或派生类。子类可以访问父类中的非私有成员(即public、protected和默认访问级别的成员),并且可以扩展父类中的属性和方法,也可以重写父类中的方法。
在继承中,子类继承了父类的属性和方法,可以使用父类的实例变量和方法,从而减少代码的冗余。另外,继承还可以实现代码的重用和扩展,即子类可以扩展父类的属性和方法,并添加新的属性和方法。
使用继承时,需要明确父类和子类之间的关系,确保继承关系的正确性和可读性。
父类应该是稳定、可靠的基类,子类应该是特定的派生类。因此,在定义父类时,需要遵循单一职责原则,尽量保持类的简洁和高内聚性。
在使用继承时,需要考虑代码的可维护性和可扩展性。因此,需要注意继承层数的问题,以及如何避免过度使用继承。
在子类中覆盖父类的方法时,需要遵循里氏替换原则,确保子类对象可以替换父类对象,而不会影响代码的正确性。
在使用继承时,需要注意多态性的应用,即子类对象可以赋值给父类引用,从而实现不同的行为。
在定义父类和子类的属性和方法时,需要考虑访问修饰符的问题,以便确保代码的封装性和安全性。
在 Java 中,父类的属性和方法一般使用访问修饰符 protected 或 public 。
Java 中的多态性指的是同一种类型的对象,在不同的情况下会表现出不同的行为。具体来说,多态性可以分为两种类型:静态多态性和动态多态性。
静态多态性是指在编译期确定调用哪个方法,例如方法重载(overloading),即一个类中定义了多个方法,它们具有相同的名称,但是参数列表不同。在调用这些方法时,编译器会根据参数列表的不同选择相应的方法。
动态多态性是指在运行期根据实际情况选择调用哪个方法,例如方法重写(overriding),即子类重写了父类的某个方法。在调用这个方法时,编译器无法确定具体调用哪个方法,需要在运行期根据对象的实际类型来决定。
多态性可以让程序更加灵活,可以通过继承和接口实现,使代码更加模块化和可扩展。
熟悉继承和多态的概念:多态性是基于继承实现的,因此必须先掌握继承的概念和使用方法。
熟悉抽象类和接口:在实现多态性时,抽象类和接口是非常重要的工具。因此,必须熟悉如何定义和使用抽象类和接口。
理解动态绑定的概念:多态性实现的关键是动态绑定,即在运行时动态地选择适当的方法。因此,必须理解动态绑定的原理和机制。
理解重写方法的概念:在多态性中,子类可以重写父类的方法。因此,必须理解如何在子类中重写方法,以及如何在子类中调用父类的方法。
熟悉多态性的应用场景:多态性可以应用于很多场景,比如实现不同类型的数据结构、实现多种算法、实现插件架构等。因此,必须熟悉多态性的应用场景,以便在实际编程中灵活应用。
注意多态性的性能问题:多态性是基于动态绑定实现的,因此会带来一定的性能开销。因此,在设计和实现程序时,应注意多态性的性能问题,避免出现性能瓶颈。
动态绑定:Java 中的动态绑定是指在程序运行期间根据对象的实际类型进行方法调用的过程。具体来说,Java 中的动态绑定是通过虚拟方法表实现的,当程序执行时,虚拟机会根据对象的实际类型在虚拟方法表中查找方法,以确定调用哪个方法。
Java 中的动态绑定可以实现多态性,使得不同类型的对象可以以同样的方式进行方法调用,这大大提高了代码的复用性和灵活性。同时,动态绑定还可以提高代码的可维护性和可扩展性,因为只需要修改方法的实现,而不需要修改调用该方法的代码。
需要注意的是,动态绑定只适用于实例方法,静态方法和 final 方法不会被动态绑定,因为它们的调用是在编译期间就被解析的。此外,动态绑定也会带来一些性能损失,因为每次调用方法时都需要在虚拟方法表中进行查找,而这个过程是比较耗时的。