🐮🐮🐮
辛苦牛,掌握主流技术栈,包括前端后端,已经7年时间,曾在税务机关从事开发工作,目前在国企任职。希望通过自己的不断分享,可以帮助各位想或者已经走在这条路上的朋友一定的帮助
目录
前言
❤️金九银十马上就要来啦,各位小伙伴们有计划跳槽的要开始准备了,博主接下来一段时间会给大家持续更新面试题目,大家持续关注一下,感谢🙏🙏🙏
今天是最基础的面向对象相关面试题,欢迎指正
之前的面试文章链接也给到大家
金九银十面试题之Mysql
金九银十面试题之设计模式
金九银十面试题之数据结构和算法
金九银十面试题之Mybatis
金九银十面试题之《Spring Data JPA、Spring MVC、AOP》
金九银十面试题之《Spring IOC》
金九银十面试题之JUC
金九银十面试题之《并发》
金九银十面试题之《JVM》
金九银十面试题之《IO、集合》
📟 Q1:谈一谈你对面向对象的理解
面向过程让计算机有步骤地顺序做一件事,是过程化思维,使用面向过程语言开发大型项目,软件复用 和维护存在很大问题,模块之间耦合严重。面向对象相对面向过程更适合解决规模较大的问题,可以拆 解问题复杂度,对现实事物进行抽象并映射为开发对象,更接近人的思维。
例如开⻔这个动作,面向过程是 open(Door door),动宾结构,door 作为操作对象的参数传入方法,方法内定义开⻔的具体步骤。面向对象的方式首先会定义一个类 Door,抽象出⻔的属性(如尺寸、颜 色)和行为(如 open 和 close),主谓结构。
面向过程代码松散,强调流程化解决问题。面向对象代码强调高内聚、低耦合,先抽象模型定义共性行 为,再解决实际问题。
📟 Q2:面向对象的三大特性?
封装是对象功能内聚的表现形式,在抽象基础上决定信息是否公开及公开等级,核心问题是以什么方式 暴漏哪些信息。主要任务是对属性、数据、敏感行为实现隐藏,对属性的访问和修改必须通过公共接口 实现。封装使对象关系变得简单,降低了代码耦合度,方便维护。
迪米特原则就是对封装的要求,即 A 模块使用 B 模块的某接口行为,对B模块中除此行为外的其他信 息知道得应尽可能少。不直接对 public 属性进行读取和修改而使用 getter/setter 方法是因为假设想在 修改属性时进行权限控制、日志记录等操作,在直接访问属性的情况下无法实现。如果将 public 的属性 和行为修改为 private 一般依赖模块都会报错,因此不知道使用哪种权限时应优先使用 private。
继承用来扩展一个类,子类可继承父类的部分属性和行为使模块具有复用性。继承是"is-a"关系,可使 用里氏替换原则判断是否满足"is-a"关系,即任何父类出现的地方子类都可以出现。如果父类引用直接 使用子类引用来代替且可以正确编译并执行,输出结果符合子类场景预期,那么说明两个类符合里氏替 换原则。
多态以封装和继承为基础,根据运行时对象实际类型使同一行为具有不同表现形式。多态指在编译层面 无法确定最终调用的方法体,在运行期由 JVM 动态绑定,调用合适的重写方法。由于重载属于静态绑 定,本质上重载结果是完全不同的方法,因此多态一般专指重写。
📟 Q3:重载和重写的区别?
重载指方法名称相同,但参数类型个数不同,是行为水平方向不同实现。对编译器来说,方法名称和参 数列表组成了一个唯一键,称为方法签名,JVM 通过方法签名决定调用哪种重载方法。不管继承关系如 何复杂,重载在编译时可以根据规则知道调用哪种目标方法,因此属于静态绑定。
JVM 在重载方法中选择合适方法的顺序:
- 精确匹配。
- 基本数据类型自动转换成更大表示范围。
- 自动拆箱与装箱。
- 子类向上转型。
- 可变参数。
重写指子类实现接口或继承父类时,保持方法签名完全相同,实现不同方法体,是行为垂直方向不同实现。
元空间有一个方法表保存方法信息,如果子类重写了父类的方法,则方法表中的方法引用会指向子类实 现。父类引用执行子类方法时无法调用子类存在而父类不存在的方法。
重写方法访问权限不能变小,返回类型和抛出的异常类型不能变大,必须加 @Override 。
📟 Q4:类之间有哪些关系?
类关系 | 描述 | 权力强 侧 | 举例 |
---|---|---|---|
继承 | 父子类之间的关系:is-a | 父类 | 小狗继承于动物 |
实现 | 接口和实现类之间的关系: can-do | 接口 | 小狗实现了狗叫接口 |
组合 | 比聚合更强的关系:contains-a | 整体 | 头是身体的一部分 |
聚合 | 暂时组装的关系:has-a | 组装方 | 小狗和绳子是暂时的聚合关系 |
依赖 | 一个类用到另一个:depends-a | 被依赖方 | 人养小狗,人依赖于小狗 |
关联 | 平等的使用关系:links-a | 平等 | 人使用卡消费,卡可以提取人的信息 |
📟 Q5:Object 类有哪些方法?
equals:检测对象是否相等,默认使用 == 比较对象引用,可以重写 equals 方法自定义比较规则。
equals 方法规范:自反性、对称性、传递性、一致性、对于任何非空引用 x,x.equals(null) 返回 false。
hashCode:散列码是由对象导出的一个整型值,没有规律,每个对象都有默认散列码,值由对象存储 地址得出。字符串散列码由内容导出,值可能相同。为了在集合中正确使用,一般需要同时重写 equals 和 hashCode,要求 equals 相同 hashCode 必须相同,hashCode 相同 equals 未必相同,因此 hashCode 是对象相等的必要不充分条件。
toString:打印对象时默认的方法,如果没有重写打印的是表示对象值的一个字符串。
clone:clone 方法声明为 protected,类只能通过该方法克隆它自己的对象,如果希望其他类也能调用 该方法必须定义该方法为 public。如果一个对象的类没有实现 Cloneable 接口,该对象调用 clone 方抛 出一个 CloneNotSupport 异常。默认的 clone 方法是浅拷⻉,一般重写 clone 方法需要实现Cloneable 接口并指定访问修饰符为 public。
finalize:确定一个对象死亡至少要经过两次标记,如果对象在可达性分析后发现没有与 GC Roots 连接 的引用链会被第一次标记,随后进行一次筛选,条件是对象是否有必要执行 finalize 方法。假如对象没 有重写该方法或方法已被虚拟机调用,都视为没有必要执行。如果有必要执行,对象会被放置在 F- Queue 队列,由一条低调度优先级的 Finalizer 线程去执行。虚拟机会触发该方法但不保证会结束,这 是为了防止某个对象的 finalize 方法执行缓慢或发生死循环。只要对象在 finalize 方法中重新与引用链 上的对象建立关联就会在第二次标记时被移出回收集合。由于运行代价高昂且无法保证调用顺序,在 JDK 9 被标记为过时方法,并不适合释放资源。
getClass:返回包含对象信息的类对象。
wait / notify / notifyAll:阻塞或唤醒持有该对象锁的线程。
📟 Q6:内部类的作用是什么,有哪些分类?
内部类可对同一包中其他类隐藏,内部类方法可以访问定义这个内部类的作用域中的数据,包括 private 数据。
内部类是一个编译器现象,与虚拟机无关。编译器会把内部类转换成常规的类文件,用 $ 分隔外部类名 与内部类名,其中匿名内部类使用数字编号,虚拟机对此一无所知。
静态内部类: 属于外部类,只加载一次。作用域仅在包内,可通过 外部类名.内部类名 直接访问,类内只 能访问外部类所有静态属性和方法。HashMap 的 Node 节点,ReentrantLock 中的 Sync 类, ArrayList 的 SubList 都是静态内部类。内部类中还可以定义内部类,如 ThreadLoacl 静态内部类 ThreadLoaclMap 中定义了内部类 Entry。
成员内部类: 属于外部类的每个对象,随对象一起加载。不可以定义静态成员和方法,可访问外部类的所 有内容。
局部内部类: 定义在方法内,不能声明访问修饰符,只能定义实例成员变量和实例方法,作用范围仅在声 明类的代码块中。
匿名内部类: 只用一次的没有名字的类,可以简化代码,创建的对象类型相当于 new 的类的子类类 型。用于实现事件监听和其他回调。
📟 Q7:访问权限控制符有哪些?
访问权限控制符 | 本类 | 包内 | 包外子类 | 任何地方 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
无 | √ | √ | × | × |
private | √ | × | × | × |
📟 Q8:接口和抽象类的异同?
接口和抽象类对实体类进行更高层次的抽象,仅定义公共行为和特征。
语法维度 | 抽象类 | 接口 |
---|---|---|
成员变量 | 无特殊要求 | 默认 public static final 常量 |
构造方法 | 有构造方法,不能实例化 | 没有构造方法,不能实例化 |
方法 | 抽象类可以没有抽象方法,但有抽象方法一定是抽象类。 | 默认 public abstract,JDK8 支持默认/静态方 法,JDK9 支持私有方法。 |
继承 | 单继承 | 多继承 |
📟 Q9:接口和抽象类应该怎么选择?
抽象类体现 is-a 关系,接口体现 can-do 关系。与接口相比,抽象类通常是对同类事物相对具体的抽象。
抽象类是模板式设计,包含一组具体特征,例如某汽⻋,底盘、控制电路等是抽象出来的共同特征,但内饰、显示屏、座椅材质可以根据不同级别配置存在不同实现。
接口是契约式设计,是开放的,定义了方法名、参数、返回值、抛出的异常类型,谁都可以实现它,但必须遵守接口的约定。例如所有⻋辆都必须实现刹⻋这种强制规范。
接口是顶级类,抽象类在接口下面的第二层,对接口进行了组合,然后实现部分接口。当纠结定义接口 和抽象类时,推荐定义为接口,遵循接口隔离原则,按维度划分成多个接口,再利用抽象类去实现这 些,方便后续的扩展和重构。
例如 Plane 和 Bird 都有 fly 方法,应把 fly 定义为接口,而不是抽象类的抽象方法再继承,因为除了 fly 行为外 Plane 和 Bird 间很难再找到其他共同特征。
📟 Q10:子类初始化的顺序
- 父类静态代码块和静态变量。
- 子类静态代码块和静态变量。
- 父类普通代码块和普通变量。
- 父类构造方法。
- 子类普通代码块和普通变量。
- 子类构造方法。
写在最后
希望博主收集的内容能帮到大家,祝大家能找到一个好的工作,过好的生活,如有错误欢迎指正。 💐💐💐