面向对象简答题整理【个人向】
0.试用面向对象语言简述改写和重定义的异同,以及方法绑定时的差别
- 改写是子类的方法和父类的方法具有相同的方法名和类型签名
- 重定义是子类的方法和父类的方法方法名相同但类型签名不同
- 在方法绑定时,改写是动态绑定,重定义是静态绑定
1.试用面向对象语言简述this的多态性
在类A的方法中,this指代类A,在类B的方法中,this指代类B
2. 试用面向对象语言简述替换原则
如果类B是类A的子类,那么无论任何时候用类B来代替类A,外界都毫无察觉,那么就称类B符合替换原则
3.为什么要尽量使用组合复用而不要用继承复用
类的内部细节对外不可见,封装性好,同时类之间的相互依赖性比较小,低耦合,因此优先使用组合可以让系统的重用性和简单性更好,而随后使用继承,可以扩展可用的组合类集 。
- 黑/白盒(可见性) 2.封装性 3.耦合性 4.简单性和重用性(继承可能产生很多类)
4. 简述重载方法绑定的步骤
- 第一步,找精确匹配(形参实参精确匹配的同一类型)找到,则执行,找不到转第二步。
- 第二步,找可行匹配(符合替换原则的匹配,即实参所属类是形参所属类的子类),没找到可行匹配,报错;只找到一个可行匹配,执行可行匹配对应的方法;如果有多于一个的可行匹配,转第三步。
- 第三步,多个可行匹配两两比较,如果一个方法的各个形参,或者:与另一个方法对应位置形参所属类相同,或者:形参所属类是另一个方法对应位置形参所属类的子类,该方法淘汰另一个方法。
- 最后,如果只剩一个幸存者,执行;如果多于一个幸存者,报错。
5. 简述多态的含义以及四种表现形式
- 多态性是指一般类中定义的方法或变量,在特殊类中不改变其名称,但通过各自不同的实现之后,可以有不同的行为或者数据类型。(后者被称为多态变量)
- 概括地讲,多态是指能够在不同上下文中,对某一事物赋予不同含义或用法。
四种表现形式:
- 重载:同一个类中,相同方法名,签名不同。在编译时解析
- 改写:子类中的方法与父类中方法的方法名、签名都相同。
- 多态变量:指可以引用多种对象类型的变量,这种变量在程序执行过程中可以包含不同类型的数值。对于动态类型语言,所有变量都可能是多态的;对于静态类型语言,则是替换原则的具体体现。
- 模板:用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。
6.代码复用的形式,各自的优缺点
组合 继承
组合的好处
组合的坏处
继承的好处
继承的坏处
7. 8种继承方式的含义以及为什么不提倡其中的某几种
特殊化:子类是父类的一个特例,即子类是父类的一个子类型
规范化:父类中定义的行为在子类中实现,而父类本身没有实现这些行为
构造:子类使用父类提供的行为,但是并不是父类的子类型。
泛化:子类修改或改写父类的某些方法
扩展:子类添加一些新功能,但没有改变继承来的行为
限制:子类限制了一些来自父类的方法的使用
变体:子类和父类之间都是对方的变体,可以任意选择两个之间的父子关系
合并:子类从多个父类中继承特性
8.重置(改写)和重载的区别,各自的优缺点
重载:同一个类定义中有多个同名的方法,但有不同的形参,而且每个方法有不同的方法体,调用时根据形参的个数、顺序和类型来决定调用的是哪个方法。
改写:子类中的方法与父类中方法的方法名,签名都相同
ps.重载是在编译时执行的,而改写是在运行时选择的
重载:
改写:
9.动态绑定和静态绑定的特点,区别
相应消息时,如果决定调用哪个方法时通过接收器当前的动态类来确定,被称为动态方法绑定,反之被称为静态方法绑定
10.什么是单继承,什么是多继承。各自的特点,如果让你设计一个程序设计语言,你会使用哪种,为什么?
单继承:一个对象只能有一个父类,继承该父类的数据和行为
多继承:一个对象可以有两个或更多不同的父类,并可以继承每个父类的数据和行为
多重继承中存在的问题:名字冲突
单继承:代码重用,减少创建类的成本,每个子类都拥有父类的方法和属性;提高代码的可扩展性……
11. 策略模式优点?
12. 分配内存的三种方式
13.构造函数的两项主要任务
- 创建对象。任何一个对象创建时,都需要初始化才能使用,所以任何类想要创建实例对象就必须具有构造函数。
- 对象初始化。构造函数可以对对象进行初始化,并且是给与之格式(参数列表)相符合的对象初始化,是具有一定针对性的初始化函数。
14. 任何消息传递表达式都有3个确定的部分
任何消息传递表达式都有 3 个确定的部分,包括接收器(receiver,消息传递的目的对象)消息选择器(message selector,表示待传递的特定的消息文本)和用于响应消息的参数(argument)。
15.通过什么检验两个概念是否为继承关系
通过 (is-a)检验规则 检验两个概念是否为继承关系
16.封装的定义
面向对象开发技术04_类和方法
17.简单工厂和工厂模式的区别
18.简述7种面向对象的设计原则
开闭原则:对扩展开放,对修改封闭。
OCP
抽象化是开闭原则的关键。
依赖倒转原则:高层模块不依赖于低层模块,他们共同依赖于抽象;细节依赖于抽象,而抽象不依赖于细节。
要求程序中所有依赖关系都应该终止于抽象类和接口。
核心思想:面向接口编程
DIOP
单一职责原则:每一个类只有单一的职责或只有一个引起变化的原因。
核心思想:高内聚,低耦合。
SRP
接口隔离原则:用功能全的大接口不如使用多个功能专一的小接口。一个类对另一个类的依赖性应该建立在最小的接口上。
核心思想:不强迫类去实现他们用不到的方法。
与单一职责原则的区别:单一职责原则针对的是单个类,接口隔离原则针对的是类与类之间的耦合关系。
ISP
组合复用原则:优先使用组合复用而不是继承来实现复用的目的。
迪米特法则:最小知识原则,一个对象应该尽可能少地了解其他对象的信息(只与朋友类进行通信)。
里式替换原则:子类在任何场合下都能够替代父类。
LSP
19.简述11种常用的设计模式
简单工厂模式:
包括(客户端)、工厂角色、抽象产品角色、具体产品角色
核心思想:有一个专门的类来负责创建实例的过程。
工厂角色返回的是父类引用,代码简单,而且符合依赖倒转原则。
应用场景:(1)工厂类负责创建的对象比较少
(2)客户只传入参数,对于创建对象(逻辑)不关心。
优点:实现了责任分割
(1)利用判断逻辑,决定实例化哪一个产品类
(2)用户无需了解产品的创建,直接根据工厂类创建所需实例。
缺点:有限地支持开闭原则,对工厂角色来说违反,丧失了灵活性和可维护性;对用户来说成立。(问题在于所有 具体产品对象的创建都放在一个类里,一旦增加新的产品,工厂类就要被修改。)
工厂方法模式:
实质是定义一个抽象的工厂接口,而将实际创建工作推迟到子类(即具体的工厂类)中。
是简单工厂模式的进一步抽象和推广,更好地支持了开闭原则。增加新的产品只需要增加新的具体工厂类。
封装了创建具体对象的工作,符合高内聚、低耦合。
抽象工厂模式:
产品族和产品等级结构
其与工厂方法模式的异同。
单例模式:
描述:某一个类只有一个实例,而且自行实例化(构造方法被设置为私有的,确保在类以外不会被初始化),并向整个系统(所有其他的类)提供这个实例。
代理模式:用代理对象来实现不直接操作对象,而对其进行访问。
实际操作对象和代理对象实现同样的功能接口。客户端保存一个功能接口的引用,指向代理对象。
装饰者模式:给某个对象(而不是整个类)动态地添加一些额外的职责
组件、具体组件、抽象装饰者、具体装饰者
组合:组件接口与抽象装饰者
桥梁模式:将抽象和实现解耦,是两者得以独立地变化。
抽象器、扩充抽象器、实现器接口、具体实现器
组合:抽象器与实现器接口
观察者模式:给对象间定义一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都能得到通知并被自动更新。
提供了目标和观察者之间的松耦合设计。
责任链模式:
适用环境:(1)有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻决定。
(2)在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
(3)可动态指定一组对象处理请求。
优点:
降低耦合度;可简化对象的互相连接;增强给对象指派职责的灵活性;增加新的请求处理类很方便。
缺点:
不能保证请求一定被接收;系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。
举例:java中的异常处理机制
组合:抽象处理者与其自身
策略模式:把一系列算法封装起来,使他们可以相互替换,这样就使得算法可以独立于调用它的客户而变化。
环境类、抽象策略类(接口)、具体策略类
组合:环境类与抽象策略类
适配器模式:
描述:将一个类的接口转换成客户希望的另外一个接口。
使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
背景:由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不能满足的。
分为类适配器(用中间类去继承已有类并扩展、同时实现环境要求的接口)和对象适配器(改为中间类持有已有类的对象,即已有类是中间类的成员变量)(保持了封装性,而且更灵活,体现了组合复用原则)
20.封装的作用与原则
- 将变化隔离;
- 便于使用;
- 提高复用性;
- 提高安全性
原则:
- 将不需要对外提供的内容都隐藏起来;
- 将属性隐藏,提供公共方法对其访问。
21.静态类型语言/动态类型语言
动态类型语言:
- 类型的检查是在运行时做的;
- 一般在变量使用之前不需要声明变量类型,而变量的类型通常是由被赋的值的类型决定。
- 优点是方便阅读,不需要写非常多的类型相关的代码
- 缺点是不方便调试,命名不规范时会造成读不懂,不利于理解等
静态类型语言:
- 类型的检查是在编译时做的.
- 在编译时,便需要确定类型的语言。即写程序时需要明确声明变量类型。
- 优点在于其结构非常规范,便于调试,方便类型安全;
- 缺点是为此需要写更多的类型相关代码,导致不便于阅读、不清晰明了
- 编译时作出内存分配决定。不必运行时刻重新分配。
22.继承的作用
23.什么是向上转型
向上转型时,父类引用指向子类对象会遗失与父类对象共有之外的其他方法,也就是在转型过程中,子类的新有的方法都会遗失掉,在编译时,系统会提示找不到方法的错误。
24.静态类型和动态类型的区别
- 对于静态类型面向对象编程语言,在编译时消息传递表达式的合法性(调用的合法性)不是基于接收器的当前动态数值,而是基于接收器的静态类来决定的。
- 运行时执行动态类所具有类型的方法
- 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;
- 如果有,再去调用子类的该同名方法。
25.强制、转换和造型区别
强制是一种隐式的类型转换,它发生在无需显式引用的程序中。
转换表示程序员所进行的显式类型转换。在许多语言里这种转换操作称为“造型”。
26.什么是多态变量,有哪四种形式
如果方法所执行的消息绑定是由最近赋值给变量的数值的类型来决定的,那么就称这个变量是多态的。
-
多态变量是指可以引用多种对象类型的变量。
-
这种变量在程序执行过程可以包含不同类型的数值。
-
对于动态类型语言,所有的变量都可能是多态的。
-
对于静态类型语言,多态变量则是替换原则的具体表现。
形式:
- 简单变量
- 接收器变量
- 向下造型(反多态)
- 纯多态(多态方法)
27.方法的改写/覆盖/重置与重载的区别
- 方法的改写/覆盖是子类和父类之间的关系,而重载一般是同一类内部多个方法间的关系
- 方法的改写/覆盖一般是两个方法间的,而重载时可能有多个重载方法
- 改写/覆盖的方法有相同的方法名和形参表,而重载的方法只能有相同的方法名,不能有相同的形参表
- 改写/覆盖时区分方法的是根据被调用方法的对象,而重载是根据参数来决定调用的是哪个方法
- 用final修饰的方法是不能被子类覆盖的,只能被重载
28.浅克隆和深克隆
浅复制(shallow copy):共享实例变量,原有变量和复制产生的变量引用相同的变量值
深复制(deep copy):建立实例变量的新的副本。
29. 方法的动态绑定过程
- 编译器检查对象的声明类型和方法名。假设我们调用x.f(args)方法,并且x已经被声明为C类的变量,那么编译器会列举出C类中所有的名称为f的方法和从C类的超类继承过来的f方法
- 接下来编译器检查方法调用中提供的参数类型。如果在所有名称为f 的方法中有一个参数类型和调用提供的参数类型最为匹配,那么就确定调用这个方法( 重载解析)
- 当程序运行并且使用动态绑定调用方法时,虚拟机必须调用同x所指向的对象的实际类型相匹配的方法版本。假设实际类型为D(C的子类),如果D类定义了f(args)那么该方法被调用,否则就在D的超类中搜寻方法f(args),依次类推
30.泛型的好处
- 避免由于数据类型的不同导致方法或类的重载。
- 类型安全。 泛型的一个主要目标就是提高程序的类型安全。使用泛型可以使编译器知道变量的类型限制,进而可以在更高程度上验证类型假设。如果没有泛型,那么类型的安全性主要由程序员来把握,这显然不如带有泛型的程序安全性高。
- 消除强制类型转换。泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。
- 多态的另一种表现形式。(参量多态)
31.耦合的种类
内部数据耦合
全局数据耦合
控制(或顺序)耦合
组件耦合
参数耦合
子类耦合
32.内聚的种类
随机内聚
逻辑内聚
时间内聚
通信内聚
顺序内聚
功能内聚
数据内聚
33.里氏原则含义
- 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
- 子类中可以增加自己特有的方法。
- 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
34.代理模式应用
远程代理
虚拟代理
保护代理
智能引用
35.对象的性质
- 封装性
- 通信性
- 自治性
- 暂存性
- 永久性
END