OOP常见面试题笔记整理(问题和答案解析)

OOP 或面向对象编程是一种围绕“对象”概念的编程模型或范式。对象可以被视为实体的真实实例,例如类,包含类模板中指定的一些特征和行为。
在简单的语言中,一个类可以被视为蓝图或模板,基于它可以创建对象。所以对象被认为是一个类的实例,因此有时被称为“实例”。术语“特性”指的是关于对象的“内容”,术语“行为”指的是关于对象的“如何”。
例如,如果我们考虑一辆车,那么基于 OOPs 模型:

  • 类= 特定的汽车型号,例如 Audi A4、BMW I8、Maruti Suzuki Vitara Brezza 等。
  • 对象 = 任何型号的特定汽车,例如你拥有的汽车
  • 特征 = 你的车是什么颜色的?你的车底盘号是多少?等等
  • 行为 = 如何启动汽车?如何给汽车换档?等等。
在编程语言中,特性也称为数据、属性或特性,行为也称为函数、过程或方法。
“对象”的概念允许 OOPs 模型轻松访问、使用和修改实例数据和方法,与其他对象交互,并在运行时(程序执行期间)定义方法。这赋予了 OOP 模型意义,并使其在实现中多样化。
事实上,OOPs 模型是如此流行,以至于许多最广泛使用的编程语言都支持并使用这种面向对象编程或 OOPs 模型,例如 Java、C++、Python、C# 等。
基本的OOP常见面试题有哪些1. 术语 OOP 是什么意思?
OOP 是指面向对象的编程。它是使用对象定义的编程范式。对象可以被视为具有某些特征和行为的类等实体的真实世界实例。
2. OOP常见面试题和答案合集:OOP 需要什么?
首选 OOP 的原因有很多,但其中最重要的是: 
  • OOPs 帮助用户轻松理解软件,尽管他们不知道实际的实现。
  • 使用 OOP,代码的可读性、可理解性和可维护性成倍增加。
  • 即使是非常大的软件也可以使用 OOP 轻松编写和管理。
3. 有哪些主要的面向对象编程语言?
使用并遵循面向对象编程范式或 OOP 的编程语言被称为面向对象编程语言。一些主要的面向对象编程语言包括:
  • Java
  • C++
  • Javascript
  • Python
  • PHP
4. 除了 OOP 之外,还有哪些其他的编程范式?
编程范式是指根据编程语言的特点对其进行分类的方法。主要有两种类型的编程范式:
  • 命令式编程范式
  • 声明式编程范式
【OOP常见面试题笔记整理(问题和答案解析)】现在,这些范式可以基于以下进一步分类:

1. 命令式编程范式:命令式编程侧重于如何执行程序逻辑并将控制流定义为改变程序状态的语句。这可以进一步分类为:
a)过程式编程范式:过程式编程指定了程序达到所需状态所必须采取的步骤,通常从上到下依次阅读。
b)面向对象编程或 OOP:面向对象编程 (OOP) 将程序组织为对象,其中包含一些数据并具有一些行为。
c)并行编程:并行编程范式将任务分解为子任务,并专注于同时同时执行它们。

2. 声明式编程范式:声明式编程侧重于执行什么和定义程序逻辑,而不是详细的控制流程。声明式范式可以进一步分为:
a)逻辑编程范式:逻辑编程范式是基于形式逻辑的,它是指一组表达有关如何解决问题的事实和规则的句子
b)函数式编程范式:函数式编程是一种通过应用和组合函数来构建程序的编程范式。
c)数据库编程范式:数据库编程模型用于管理结构化为字段、记录和文件的数据和信息。
5. 结构化编程是什么意思?
结构化编程是指由完全结构化的控制流组成的编程方法。这里的结构是指一个块,它包含一组规则,并具有明确的控制流,例如(if/then/else)、(while和for)、块结构和子程序。
几乎所有的编程范式都包括结构化编程,包括 OOP 模型。
6. OOP 的主要特点是什么?
OOP 或面向对象编程主要包括以下四个功能,请确保你不会错过任何一个:
  • 继承
  • 封装
  • 多态性
  • 数据抽象
7. 使用 OOP 有哪些优势?
  • OOP 非常有助于解决非常复杂的问题。
  • 使用面向对象编程可以轻松创建、处理和维护高度复杂的程序。
  • OOP,促进代码重用,从而减少冗余。
  • OOP 还有助于在数据抽象的帮助下隐藏不必要的细节。
  • OOP 是基于自底向上的方法,与使用自顶向下方法的结构编程范式不同。
  • 多态性在 OOP 中提供了很大的灵活性。
8. 为什么 OOP 如此受欢迎?
OOPs 编程范式被认为是一种更好的编程风格。它不仅有助于轻松编写复杂的代码,而且还允许用户轻松处理和维护它们。不仅如此,OOP 的主要支柱——数据抽象、封装、继承和多态,让程序员可以轻松解决复杂的场景。因此,OOP 非常流行。
高级 OOP 面试问题9. 什么是类?
类可以理解为模板或蓝图,其中包含一些值,称为成员数据或成员,以及一些规则集,称为行为或函数。所以当一个对象被创建时,它会自动获取类中定义的数据和函数。
因此,类基本上是对象的模板或蓝图。也可以根据一个类创建任意数量的对象。
例如,首先创建汽车的模板。然后根据该模板创建多个汽车单元。
10. 什么是对象?
一个对象是指类的实例,它包含类模板中定义的成员和行为的实例。在现实世界中,对象是用户与之交互的实际实体,而类只是该对象的蓝图。所以对象消耗空间并具有一些特征行为。
例如,特定的汽车。
11.什么是封装?
人们可以将封装可视化为一种将完成工作所需的所有内容放入胶囊并将该胶囊呈现给用户的方法。这意味着通过封装,所有必要的数据和方法都绑定在一起,所有不必要的细节对普通用户隐藏。所以封装是将程序的数据成员和方法绑定在一起以完成特定工作的过程,而不会透露不必要的细节。

封装也可以用两种不同的方式定义:

1)数据隐藏:封装是隐藏不需要的信息的过程,例如限制对对象任何成员的访问。

2)数据绑定:  封装是将数据成员和方法作为一个整体、作为一个类绑定在一起的过程。
12. 什么是多态?
多态性由两个词组成——“poly”,意思是“许多”,“morph”,意思是“形状”。因此,多态性是指具有多种形状的东西。
在 OOP 中,多态是指某些代码、数据、方法或对象在不同的??环境或上下文中表现不同的过程。编译时多态性和运行时多态性是 OOP 语言中的两种多态性。
13.什么是编译时多态,它与运行时多态有什么不同?
编译时多态:编译时多态,也称为静态多态,是指在编译时发生的多态类型。这意味着编译器决定图片中的实体必须采用什么形状或值。
例子:
// In this program, we will see how multiple functions are created with the same name, // but the compiler decides which function to call easily at the compile time itself. class CompileTimePolymorphism{ // 1st method with name add public int add(int x, int y){ return x+y; } // 2nd method with name add public int add(int x, int y, int z){ return x+y+z; } // 3rd method with name add public int add(double x, int y){ return (int)x+y; } // 4th method with name add public int add(int x, double y){ return x+(int)y; } } class Test{ public static void main(String[ ] args){ CompileTimePolymorphism demo=new CompileTimePolymorphism(); // In the below statement, the Compiler looks at the argument types and decides to call method 1 System.out.println(demo.add(2,3)); // Similarly, in the below statement, the compiler calls method 2 System.out.println(demo.add(2,3,4)); // Similarly, in the below statement, the compiler calls method 4 System.out.println(demo.add(2,3.4)); // Similarly, in the below statement, the compiler calls method 3 System.out.println(demo.add(2.5,3)); } }

在上面的例子中,有四个版本的 add 方法。第一种方法需要两个参数,而第二种方法需要三个。对于第三种和第四种方法,参数顺序发生了变化。编译器查看方法签名并决定在编译时为特定方法调用调用哪个方法。

运行时多态性:运行时多态性也称为动态多态性,是指在运行时发生的多态性类型。这意味着它不能由编译器决定。因此,必须采取何种形式或价值取决于执行。因此名称为运行时多态性。
例子:
class AnyVehicle{ public void move(){ System.out.println(“Any vehicle should move!!”); } } class Bike extends AnyVehicle{ public void move(){ System.out.println(“Bike can move too!!”); } } class Test{ public static void main(String[ ] args){ AnyVehicle vehicle = new Bike(); // In the above statement, as you can see, the object vehicle is of type AnyVehicle // But the output of the below statement will be “Bike can move too!!”, // because the actual implementation of object ‘vehicle’ is decided during runtime vehicle.move(); vehicle = new AnyVehicle(); // Now, the output of the below statement will be “Any vehicle should move!!”, vehicle.move(); } }

由于调用的方法是在运行时确定的,如上面的代码所示,这称为运行时多态。 
14. OOP常见面试题有哪些:C++是如何支持多态的?
C++ 是一种面向对象的编程语言,它也支持多态:
  • 编译时多态性:C++ 借助模板、函数重载和默认参数等功能支持编译时多态性。
  • 运行时多态性:  C++ 借助虚函数等特性支持运行时多态性。虚函数根据引用的对象类型采用函数的形状,并在运行时解析。
15.继承是什么意思?
“继承”一词的意思是“从父母那里获得某种品质或行为给后代”。在面向对象的编程中,继承是使用另一个对象或类(称为父类)的定义创建对象或类(称为子类)的机制。继承不仅有助于保持实现更简单,而且有助于促进代码重用。
16. 什么是抽象?
如果你是用户,并且有问题陈述,你不想知道软件的组件是如何工作的,或者它是如何制作的。你只想知道该软件如何解决你的问题。抽象是从必要的细节中隐藏不必要的细节的方法。它是 OOP 的主要特性之一。 
例如,考虑一辆汽车。你只需要知道如何驾驶汽车,而不需要知道车内的电线是如何连接的。这是使用抽象获得的。
17.一个类占用多少内存?
类不消耗任何内存。它们只是基于创建对象的蓝图。现在,当创建对象时,它们实际上会初始化类成员和方法,因此会消耗内存。
18. 总是需要从类创建对象吗?
不可以。如果基类具有非静态方法,则必须创建一个对象。但是如果类有静态方法,则不需要创建对象。在这种情况下,你可以使用类名直接调用类方法。
19. 什么是构造函数?
构造函数是名称与类名相同的特殊方法。构造函数用于初始化对象的特殊目的。
例如,假设有一个名为“MyClass”的类,那么当你实例化这个类时,你传递的语法是:
MyClass myClassObject = new MyClass();
现在这里,在“new”关键字之后调用的方法——MyClass(),就是这个类的构造函数。这将有助于实例化成员数据和方法并将它们分配给对象 myClassObject。
20. OOP常见面试题和答案合集:C++中有哪些类型的构造函数?
最常见的构造函数分类包括:
默认构造函数:默认构造函数是不带任何参数的构造函数。它没有参数。
class ABC { int x; ABC() { x = 0; } }

参数化构造函数:接受某些参数的构造函数称为参数化构造函数。
class ABC { int x; ABC(int y) { x = y; } }

复制构造函数:复制构造函数是一个成员函数,它使用同一类的另一个对象来初始化一个对象。
class ABC { int x; ABC(int y) { x = y; } // Copy constructor ABC(ABC abc) { x = abc.x; } }

21. 什么是复制构造函数?
复制构造函数是构造函数的一种,其目的是将一个对象复制到另一个对象。这意味着复制构造函数将克隆一个对象并将其值克隆到另一个对象中,前提是这两个对象属于同一类。
22. 什么是析构函数?
与初始化对象并为其指定空间的构造函数相反,析构函数也是特殊的方法。但是析构函数释放对象占用的资源和内存。当对象被销毁时会自动调用析构函数。 
23. 类和结构相同吗?如果不是,类和结构之间有什么区别?
不,类和结构不一样。尽管它们看起来相似,但它们之间的差异使它们与众不同。例如,结构体保存在栈内存中,而类保存在堆内存中。此外,数据抽象不能借助结构来实现,但在类的帮助下,主要使用抽象。
24. 举例说明继承?
继承是面向对象编程的主要特征之一,通过它一个实体继承了另一个实体的一些特征和行为,并使它们成为自己的。继承有助于改进和促进代码重用。
我用一个常见的例子给你解释一下。让我们以三种不同的车辆为例——汽车、卡车或公共汽车。这三者完全不同,具有各自特定的特征和行为。但。在这三者中,你会发现一些共同的元素,比如方向盘、油门、离合器、刹车等。虽然这些元素用在不同的车辆上,但它们仍然有自己的特点,在所有车辆中都是通用的。这是通过继承实现的。汽车、卡车和公共汽车都继承了方向盘、油门、离合器、制动器等特性,并把它们当作自己的。因此,他们不必从头开始创建这些组件,从而促进代码重用。
25. 继承有什么限制吗?
是的,权力越大,并发症就越多。继承是 OOP 中一个非常强大的特性,但它也有一些限制。继承需要更多的时间来处理,因为它需要在多个类中导航才能实现。此外,继承中涉及的类——基类和子类,非常紧密地耦合在一起。因此,如果需要进行一些更改,他们可能需要在两个类中进行嵌套更改。继承对于实现来说也可能很复杂。因此,如果没有正确实施,这可能会导致意外错误或不正确的输出。
26. 继承的种类有哪些?
各种类型的继承包括:
  • 单继承
  • 多重继承
  • 多级继承
  • 层次继承
  • 混合继承
27. 什么是子类?
子类是继承的一部分。子类是一个实体,它继承自另一个类。它也被称为子类。
28.定义一个超类?
超类也是继承的一部分。超类是一个实体,它允许子类或子类从自身继承。
29. 什么是接口?
接口指的是一种特殊类型的类,它包含方法,但不包含它们的定义。接口中只允许声明方法。要使用接口,你不能创建对象。相反,你需要实现该接口并定义它们的实现方法。 
30.静态多态是什么意思?
静态多态通常被称为编译时多态。静态多态性是一种特性,通过该特性,对象在编译期间根据值与相应的函数或运算符链接。静态或编译时多态可以通过方法重载或运算符重载来实现。
31. 动态多态是什么意思?
动态多态或运行时多态是指 OOP 中的多态类型,通过它在运行时或执行期间决定函数的实际实现。动态或运行时多态可以在方法覆盖的帮助下实现。
32. OOP常见面试题有哪些:重载和覆盖有什么区别?
重载是一种编译时多态特性,其中一个实体具有多个同名的实现。例如,方法重载和运算符重载。
而覆盖是一种运行时多态特性,其中一个实体具有相同的名称,但其实现在执行过程中会发生变化。例如,方法覆盖。
图片
33、数据抽象是如何实现的?
数据抽象是在抽象方法或抽象类的帮助下完成的。
34.什么是抽象类?
抽象类是包含抽象方法的特殊类。抽象类的意义在于它内部的抽象方法没有实现,只有声明。所以这样一来,当子类继承了抽象类,需要使用它的抽象方法时,就需要自己定义和实现。
35. OOP常见面试题和答案合集:抽象类与接口有什么不同?
接口和抽象类都是特殊类型的类,它们只包含方法声明而不包含它们的实现。但是接口与抽象类完全不同。两者的主要区别在于,在实现接口时,子类必须定义其所有方法并提供其实现。而当抽象类被继承时,子类不需要提供其抽象方法的定义,直到并且除非子类正在使用它。
此外,抽象类可以包含抽象方法和非抽象方法。
36. 什么是访问说明符,它们的意义是什么?
访问说明符,顾名思义,是一种特殊类型的关键字,用于控制或指定类、方法等实体的可访问性。一些访问说明符或访问修饰符包括“private”、“public”、等等。这些访问说明符在实现封装方面也起着非常重要的作用——封装是 OOP 的主要特性之一。
37. 什么是异常?
异常可以被视为一种特殊事件,它在运行时执行程序期间引发,导致执行停止。出现异常的原因主要是由于程序中的某个位置,用户想要做一些程序未指定的事情,例如不需要的输入。
38. 异常处理是什么意思?
没有人希望其软件失败或崩溃。异常是软件失败的主要原因。可以在程序中预先处理异常并防止执行停止。这称为异常处理。
因此,异常处理是识别程序可以达到的不良状态并指定这些状态的理想结果的机制。
Try-catch 是程序中处理异常最常用的方法。
39. OOPs 世界中的垃圾回收是什么意思?
面向对象的编程围绕着像对象这样的实体展开。每个对象都消耗内存,一个类可以有多个对象。因此,如果这些对象及其内存处理不当,则可能会导致某些与内存相关的错误,系统可能会出现故障。
垃圾回收就是指这种在程序中处理内存的机制。通过垃圾收集,通过删除不再需要的对象来释放不需要的内存。
40. 我们可以在不实现 OOP 概念的情况下运行 Java 应用程序吗?
不可以。Java 应用程序基于面向对象的编程模型或 OOP 概念,因此没有它就无法实现。
然而,另一方面,C++ 可以在没有 OOP 的情况下实现,因为它也支持类似 C 的结构化编程模型。
编码问题:OOP常见面试题和答案合集41. 下面代码的输出是什么?
#include< iostream> using namespace std; class BaseClass1 { public: BaseClass1() { cout < < " BaseClass1 constructor called" < < endl; } }; class BaseClass2 { public: BaseClass2() { cout < < "BaseClass2 constructor called" < < endl; } }; class DerivedClass: public BaseClass1, public BaseClass2 { public: DerivedClass() {cout < < "DerivedClass constructor called" < < endl; } }; int main() { DerivedClass derived_class; return 0; }

输出:
BaseClass1 constructor called BaseClass2 constructor called DerivedClass constructor called

原因:
上面的程序演示了多重继承。所以当Derived类的构造函数被调用时,它会自动从左到右的继承顺序调用Base类的构造函数。
42. 下面代码的输出是什么?
class Scaler { static int i; static { System.out.println(“a”); i = 100; } }public class StaticBlock { static { System.out.println(“b”); }public static void main(String[ ] args) { System.out.println(“c”); System.out.println(Scaler.i); } }

输出:
b c a 100

原因:
首先会实现主方法调用类中的静态块。因此将首先打印 'b'。然后调用 main 方法,现在按预期保持顺序。
43. 预测输出?
#include< iostream> using namespace std; class ClassA { public: ClassA(int ii = 0) : i(ii) {} void show() { cout < < "i = " < < i < < endl; } private: int i; }; class ClassB { public: ClassB(int xx) : x(xx) {} operator ClassA() const { return ClassA(x); } private: int x; }; void g(ClassA a) {a.show(); } int main() { ClassB b(10); g(b); g(20); getchar(); return 0; }

输出:
i = 10 i = 20

原因:
ClassA 包含一个转换构造函数。因此,ClassA 的对象可以具有整数值。所以语句 g(20) 有效。此外,ClassB 有一个重载的转换运算符。所以语句 g(b) 也适用。
44. 下面代码的输出是什么?
public class Demo{ public static void main(String[ ] arr){ System.out.println(“Main1”); } public static void main(String arr){ System.out.println(“Main2”); } }

输出:
Main1

原因:
这里的 main() 方法被重载了。但是 JVM 只理解在其定义中有一个 String[] 参数的 main 方法。因此打印 Main1 并忽略重载的 main 方法。 
45. 预测输出?
#include< iostream> using namespace std; class BaseClass{ int arr[ 10]; }; class DerivedBaseClass1: public BaseClass { }; class DerivedBaseClass2: public BaseClass { }; class DerivedClass: public DerivedBaseClass1, public DerivedBaseClass2{}; int main(void) { cout< < sizeof(DerivedClass); return 0; }

输出:
If the size of the integer is 4 bytes, then the output will be 80.

原因: 
由于 DerivedBaseClass1 和 DerivedBaseClass1 都继承自 BaseClass 类,DerivedClass 包含 BaseClass 的两个副本。因此,它导致空间浪费和大尺寸输出。它可以在虚拟基类的帮助下减少。
46. OOP常见面试题有哪些:下面程序的输出是什么?
#include< iostream> using namespace std; class A { public: void print() { cout < < " Inside A::"; } }; class B : public A { public: void print() { cout < < " Inside B"; } }; class C: public B { }; int main(void) { C c; c.print(); return 0; }

输出:
Inside B

原因:
上述程序实现了多级层次结构。所以程序被线性搜索,直到找到匹配的函数。在这里,它同时存在于类 A 和 B 中。因此调用了类 B 的 print() 方法。 

    推荐阅读