Java面试专题——面向对象
面向过程和面向对象的区别
面向过程:当事件比较简单的时候,利用面向过程,注重的是事件的具体的步骤/过程,注重的是过程中的具体的行为,以函数为最小单位,考虑怎么做。
面向对象:注重找“参与者”,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
二者相辅相成,并不是对立的。
解决复杂问题,可以通过面向对象方式,便于我们从宏观上把握事物之间复杂的关系;具体到微观操作,仍然使用面向过程方式来处理。
面向对象三个阶段
【1】面向对象分析OOA -- Object Oriented Analysis
- 从对象抽取出类
- 类里面有什么
- 动词--》动态特性--》方法
- 名词--》静态特性--》属性
【2】面向对象设计OOD -- Object Oriented Design
- 先有类,再有对象
【3】面向对象编程OOP -- Object Oriented Programming
如何理解Java的面向对象
面向对象编程的核心,主要是对象、类、封装、继承、多态以及抽象。
- 首先是将万事万物都看成一个个具体的对象,而类就是抽取一部分对象共同的属性、行为等构建的一个用于创建这类对象的模板;
- 封装则是为了提高数据的安全性,通过访问修饰符去控制类的相关权限;
- 继承则是通过子类继承父类的属性和方法来提高代码的复用,当然也是多态的前置条件;
- 而多态则是通过方法的重载和重写,来简化程序的调用,提高代码的灵活性和可拓展性;
- 最后则是抽象,通过抽象类和接口的方式,来解决单继承的不足,进一步提高代码的可拓展性和可维护性。
面向对象三大特性
封装(Encapsulation)
封装的本质,就是把该隐藏的隐藏起来,该暴露的暴露出来。
封装的主要目的是隐藏对象内部的复杂性和实现细节,只对外公开简单的接口。
封装是一种信息隐藏技术,在java中通过访问修饰符(如private、protected、public等)来实现,控制用户对类的修改和访问数据的程度,其中private是最严格的访问级别,它限制了类外部对类内部成员的访问。
适当的封装可以让程式码更容易理解和维护,也加强了程式码的安全性。
封装的好处:
-
提高代码的安全性:通过隐藏类的内部实现细节,封装可以防止外部代码直接访问和修改类的内部状态,从而减少了错误的发生。
-
提高代码的复用性:封装使得类的内部实现可以独立于外部使用,因此可以在不同的上下文中重用同一个类。
-
提高代码的可维护性:由于封装隐藏了类的内部实现,因此当需要修改类的内部实现时,只需要修改类的内部代码,而不需要修改使用该类的外部代码。
封装的设计,也就是所谓的“高内聚,低耦合”:
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅对外暴露少量的方法用于使用。 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。
继承(Inheritance)
继承的本质就是子类继承父类所定义的内容。
继承就是让一个类继承另一个类的属性和方法。通过继承,子类可以重用父类的代码,而不需要重新编写相同的代码。
继承是代码复用的重要手段之一,也是多态性的基础。
继承的好处:
-
提高代码的复用性:子类可以继承父类的属性和方法,从而避免了代码的重复编写。
-
便于代码的扩展:通过继承,可以在不修改父类代码的情况下,通过扩展子类来添加新的功能。
-
支持多态性:多态性是面向对象编程的一个重要特性。
注意:
在Java中,一个类只能直接继承一个父类(单继承),但可以通过多层继承来间接继承多个类。
继承具有传递性,即子类会继承父类以及父类的父类(直到Object类)的所有非私有属性和方法。
父类的私有成员(属性和方法)虽然被子类继承,但子类不能直接访问它们。子类只能通过父类提供的公共或受保护的方法来间接访问这些私有成员。
多态(Polymorphism)
多态的本质,就是通过对于同一个方法调用,然后由于其实现子类的不同,来实现不同的需求。
多态就是可以用统一的接口来操作不同的对象。当通过父类类型的引用调用方法时,由于多态的存在,会根据引用所指向的对象的实际类型来调用相应的方法,这就实现了多态。
Java中的多态通过继承和方法重写实现:
-
继承:子类通过继承获得父类的属性和方法,从而可以扩展父类的功能。
-
方法重写:子类根据需要重写父类中的方法,以改变方法的行为。
多态的设计,也就是所谓的“开闭原则”
- 对扩展是开放:可以通过实现不同子类,实现不同的能力;
- 对修改关闭:避免了修改旧代码。
类与类之间的关系
一、继承关系
继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。在Java中继承关系通过关键字extends明确标识,在设计时一般没有争议性。
在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口。
二、实现关系
实现指的是一个class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。在Java中此类关系通过关键字implements明确标识,在设计时一般没有争议性。
在UML类图设计中,实现用一条带空心三角箭头的虚线表示,从类指向实现的接口。
三、依赖关系
简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。表现在代码层面,让类B作为参数被类A在某个method方法中使用。
在UML类图设计中,依赖关系用由类A指向类B的带箭头虚线表示。
四、关联关系
关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向的。表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。
在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记。
五、聚合关系
聚合是关联关系的一种特例,它体现的是整体与部分的关系,即has-a的关系。此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。比如计算机与CPU、公司与员工的关系等,比如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。
在UML类图设计中,聚合关系以空心菱形加实线箭头表示。
六、组合关系
组合也是关联关系的一种特例,它体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束,比如人和人的大脑。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。
在UML类图设计中,组合关系以实心菱形加实线箭头表示。
七、总结
对于继承、实现这两种关系没多少疑问,它们体现的是一种类和类、或者类与接口间的纵向关系。其他的四种关系体现的是类和类、或者类与接口间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准确定位是很难的。前面也提到,这四种关系都是语义级别的,所以从代码层面并不能完全区分各种关系,但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖。