Java企业教程系列

Java面向对象面试参考指南

  Java是基于面向对象概念的语言,允许在更高抽象层次上解决现实问题j。面向对象的方法是以概念化现实世界中的对象方式解决问题,能够更容易跨应用程序重用。对象例如椅子,电风扇,狗,计算机等。

  在Java中,一个类是一个蓝图或一个模板或一个原型,定义的是相同类型对象的共同行为。一个实例是一个特定类的实现,类的所有实例都具有相似在类定义中描述的属性。例如,你可以定义一个类叫做房子,房间号码作为其属性编号,然后可以建立有2个房间房子实例,或有3个房间房子等情况。

OO优点

  面向对象软件开发的优点如下:

  • 更少的维护量,因为它是模块化的
  • 更好的代码重用,比如继承等可以加快开发。
  • 提高代码可靠性和灵活性
  • 易于理解,因为是基于现实世界建模
  • 在对象层次更好的抽象。
  • 在一个开发阶段到另外一个开发阶段切换时降低复杂性。

  OOPS主要优点:

  • 封装
  • 继承
  • 多态性
  • 抽象

封装

  封装提供了对象之间的一种合约,这种合约确定对象自身内部隐藏什么,向彼此暴露什么。在Java中,我们可以使用private访问修饰符来隐藏方法和变量,从而制约来自外部世界的访问。 Java也提供了不同的访问修饰符如public(默认),protected和private,在不同的隐藏水平使用,但目标是封装一些不需要改变的东西。按照最佳实践 - 一个类应该只有一个理由去改变,封装实现的“一个理由”的设计原则。(SRP单个职责原则)

  封装意味着隐藏预期会经常改变的一些东西,以避免这种改变破坏其它类。好处:

  • 我们能够保护内部状态,只要通过隐藏对象的属性即可,因为我们经常使用对象的一个属性来代表对象的状态。如A中的state是一种状态:
    public class A{
      private int state = 0;
    }
  • 能够提高代码的模块性,因为封装可以阻止对象和其他外部对象以一种不可预期的方式交互。
  • 提高重用性
  • 它维持特定对象的合约。
  • 封装促进维护
  • 代码能够独立地改变。

 

多态性

  多态性是一种(编程时)对于不同基础形式(数据类型)呈现相同接口的能力。这意味着类有不同的功能,同时共享一个通用的接口,可以通过传递特定类别的参考动态调用。典型的例子是Shape类和所有可以继承它(方形,圆形,十二面体,不规则的多边形,图示等)的类。每个类都有一个 Draw ()方法,客户端代码可以如下调用:


1 Shape shape=new Square ();
2  
3 Shape.area() to get the correct behavior for any shape.

  多态性的美妙之处在于与不同类别工作代码并不需要知道它正在使用哪个具体类,因为它们都使用相同的方法。采用面向对象的编程语言来实现运行时多态的过程称为动态绑定。注意:多态是一种运行时依赖调用其对象进行选择特定方法的的能力。多态性的发生可以不涉及抽象类。好处如下:

  • 创建可重用的代码:多态性意味着一旦类被创建 实现和测试,它就能容易地被使用,而无需关注类的内部写的是什么
  • 它提供更多泛型和松耦合代码
  • 编译时间更少,且允许更快地开发
  • 动态绑定:
  • 一些接口能够使用不同实现方式创建。
  • 能够使用同样的方法签名完全替代实现。

使用方法重载来实现多态性:重写处理涉及两个方法:一个在父类,而另一个在子类,并具有相同的方法名称和签名。重载让您可以为不同的对象类型以不同的方式定义同样的操作。


1 while(it.hasNext()) {
2  
3 Shape s = (Shape) it.next();
4  
5 totalArea += s.area(dim); //polymorphic method call. 多态方法调用
6  
7 }

方法重载或点对点多态性或静态多态性与重载多种方法在同一类中具有相同名称但不同的方法签名交易。重载允许您定义以不同的方式对不同数据的相同操作。有些时候它说为静态多态,但实际上它不是多态。方法重载无非有两种方法具有相同名称但不同的参数列表。它无关,与继承和多态。一个重载的方法是不一样的重写的方法。

 

继承

  基类的行为(即方法)和状态(即变量)可以在其派生子类中访问。继承的主要优点是,它提供了代码重用和避免重复继承的正式机制,这也会导致紧耦合的设计,因为如果你要更改的超类,你必须知道子类的所有细节。

好处:

  • 提高了可复用性
  • 创建了逻辑上的"is a"关系,如 Dog is a animal
  • 模块化代码
  • 避免重复

缺点:

  • 紧耦合: 子类依赖于父类实现是一种紧耦合。

UML和java继承对应:

 

抽象

  抽象意味着以接口和功能开发类,而不是功能的实现细节。抽象类暴露接口,而不是暴露实际执行细节。它从分离对象的执行实现。通过隐藏不相关的细节降低了复杂性。简单比喻:条条大路通罗马,什么途径细节通往罗马不重要,关键目标到达罗马即可,这就是抽象。

好处:

  • 通过使用抽象, 我们能将细节通过类型进行分类
  • 频繁地改变属性和方法将被分组到一个单独类型,以避免主要类型不受改变影响,这是符合 OOAD 原则 -”代码应该对扩展开发,对修改封闭”.
  • 简化领域模型的表现。

 

抽象和封装的区别

  封装是作为抽象策略的一部分。封装是指对象的状态 - 对象封装它自己的状态,并对外部将其隐藏;,该类以外的用户必须通过它的方法与状态进行交互(读写),但不能直接访问类的状态。所以类是抽象了有关其状态的实现细节。

  抽象是更通用的术语,它的实现可以由子类完成。例如,类List是一种集合抽象,List的具体子类有ArrayList或LinkedList。

  如果没有通过封装隐藏其内部状态,抽象也不可能实现,如果一个类暴露其内部状态,它不能在其内部完全掌控改变这个状态,那么这也不是抽象。

 

什么是接口

  接口是类的抽象,没有类的任何方法或函数实现的细节。你只能声明一个方法或函数的名称,但不要提供实现细节也就是如何实现这些方法。实现该接口的类应该提供实际的实现细节。接口是面向对象设计的一个非常有用和常用的概念,因为它提供了接口和实现的分离,使您能够:

  1. 多个继承
  2. 松耦合-将抽象的操作和实现分离在不同层次,比如JDBC, JPA, JTA etc.
  3. 面向接口编程,而不是面向实现细节编程
  4. 结合动态绑定的多态性 – 暴露其对象接口,而不是暴露其细节.
  5. 抽象层: 分离关注

 

组合Composition

  代码的可重用性可通过实现继承或组合等方式实现,组合方法对代码重用的提供比继承更强的封装,因为后端类的更改不需要破坏只依赖于前端类的任何代码。组合是一种"has a"的设计技术。我们可以使用Java继承或代码的重用对象的组合表达对象之间的关系。想想椅子的例子:椅子有一个座位,椅子有一个后背,椅子都有一套腿。短语“has a具有”意味着椅子上拥有的关系,至少拥有另一个对象。正是这种“has a具有”的关系是是组合的本质。

组合在UML和Java对应关系图:

组合和继承区别


No. 组合Composition (has a) 继承Inheritance (is a)
1 主张多态性和代码重用 主张多态性和代码重用
2 对象在运行时间获得完成 对象在编译时间动态获得
3 运行时间实现细节可替代 运行时间实现细节可替代
4 子类并不依赖父类,松耦合 子类依赖父类,紧耦合
5 房间有一个( has a)卫生间,但不能说房子就是(is a) 卫生间 继承是单向的,房子是is a 建筑,但建筑不是房子

 

组合Composition 与聚合aggregation区别

  • 聚合:聚合是在一个类属于一个集合的关联。其中的一部分可以在没有集合整体情况下单独存在。它是弱关系。没有循环依赖。例如:订单和产品。
  • 组合:组合也是一类属于一个集合的关联。其中的一部分在没有整体存在情况下也不能存在,如果整体被删除,则所有部分都将被删除。这是更强有力的关系。例如多边形和点,订单和订单详细。

 

Java企业系列面试题

SOLID面向对象设计原则

领域驱动设计