2 面向对象技术

2.1 面向对象与面向过程有什么区别

  面向对象是当今软件开发方法的主流方法之一,它是把数据以及对数据操作的方法放在一起,作为一个相互依存的整体,即对象。对同类对象抽象出其共性,即类。类中的大多数据只能被本类方法进行处理。类通过一个简单的接口与外界发生关系,对象与对象之间通过消息进行通讯。程序流程由用户在使用中决定。

  面向过程是一种以事件为中心的开发方法,就是自顶向下顺序执行,逐步求精,其程序结构是按照功能划分为若干个基本模块,这些模块形成一个树状结构,各模块之间关系也比较简单,在功能上也相对独立,每一个模块内部一般都是由顺序、选择、循环三种基本结构组成,其模块化具体实现是使用子程序,而程序流程在写程序时就已经决定。

面向对象与面向过程的不同之处
1)出发点不同:
  面向对象方法使用符合常规思维的方式来处理客观世界的问题,强调把问题域的要领直接映射到对象以及对象接口上 。
  面向过程方法强调的是过程的抽象画与模块化,是以过程为中心构造或处理客观世界问题。

2)层次逻辑不同:
  面向对象方法是用计算机逻辑来模拟客观世界中的物理存在,以对象的集合类作为处理问题的基本单位,用类的层次结构来体现类之间的继承和发展。
  面向过程方法处理问题的基本单位是能准确清晰的表达过程的模块,用模块层次结构来概括模块或模块间的关系与功能。

3)数据处理方式与控制程序方式不同
  面向对象的方法将数据与对应的代码封装成一个整体,原则行其他对象不能直接修改其数据,即对象的修改只能由自身的成员函数完成。
  面向对象的方法控制程序方式是通过"事件驱动"来激活和运行程序的。
  面向过程方法是直接通过程序来处理数据,处理完毕即可显示处理结果
  面向过程方法控制程序是按照设计调用或返回程序,不能自由导航,各模块之间存在着控制与被控制,调用与被调用的关系。

4)分析设计与编码转换方式不同
  面向对象方法贯穿于软件生命周期的分析、设计及编码,是一种平滑的过程,从分析到设计再到编码是采用一致性的模型表示,实现的是一种无缝连接。
  面向过程方法强调分析、设计以及编码之间按规则进行转换,贯穿于软件生命周期的分析、设计及编码,是一种有缝链接。


2.2 面向对象有哪些特征


面向对象的主要特征包括抽象、继承、封装和多态。

抽象:
  抽象就是忽略一个主题中与当前目标无关的那些方面,以便于更充分地注意到与当前目标有关的方面。抽象并不打算了解全部问题,而是选择其中的一部分
  抽象包括两个方面:过程抽象   &  数据抽象
继承:
  继承是一种联结类的层次模型,并且允许和鼓励类的重用,提供了一种明确表述共性的方法。
  对象的一个新类可以从现有的类中派生,这个过程称为继承。
  新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。
  派生类可以从它的基类那里继承方法和实例变量。
  并且派生类可以修改或增加新的方法使之更适合特殊的需要
封装:
  封装是指将客观事物抽象成类,每个类对自身数据和方法实行保护。
  类可以把自己的数据和方法只让可信任的类或者对象操作。
多态:
  多态是指允许不同类的对象对同一消息作出响应,多态包括参数多态和包含多态。
  多态性语言具有灵活、抽象、行为共享、代码共享等优势,很好解决了应用程序函数同名问题。


2.3 面向对象的开发方式有什么优点

面向对象的有点有很多,主要有三点,了解即可。
1)较高的开发效率
2)保证软件的鲁棒性
3)保证软件的高可维护性

2.4 什么是继承

  继承是一种联结类的层次模型,并且允许和鼓励类的重用,提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为继承。 新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。 派生类可以从它的基类那里继承方法和实例变量。 并且派生类可以修改或增加新的方法使之更适合特殊的需要
  继承是通过extends关键字来实现的,使用格式为: class子类名 extends 父类名。

继承主要有以下几大特性:
  1)Java语言不支持多重继承,但是可以通过实现多个接口来达到多重继承的目的
  2)子类只能继承父类的非私有成员变量与方法
  3)当子类中定义的成员变量和父类中定义的成员变量同名时,子类成员变量会覆盖父类成员变量,而不会继承。
  4)当子类中的方法与父类中的方法有相同函数签名时,子类将会覆盖父类的方法。


2.5 组合和继承有什么区别

组合和继承是面向对象中两种代码复用的方式。

组合是指在新类里面创建原有类的对象,重复利用原有类的功能。
继承是面向对象主要特性之一,它允许设计人员根据其他类的实现来定义一个的实现。
组合和继承都允许在新类中设置子对象:
   组合式显式的
   继承是隐式的
组合和继承存在着对应关系:
   组合中的整体类和继承中的子类对应
   组合中的局部类和继承中的父类对应

继承和组合都能实现代码的复用,那么在实际开发中又该如何选择使用呢?一般情况下会遵循两点原则
1)除非两个类之间的关系是 " is - a " 的关系,否则不轻易使用继承。不应该单纯的为了实现代码的重用而使用继承,因为过多的继承会破坏代码的可维护性。当父类被修改时,会影响到所有继承自它的子类,从而增加程序的维护难度与成本。

2)不应该仅仅为了实现多态而使用继承。如果类之间没有 " is - a " 的关系,可以通过实现接口与组合的方式来达到相同的目的。设计模式中的策略模式可以很好的说明这一点,采用接口与组合的方式比采用继承的方式具有更好的可扩展性。

由于Java语言只支持单继承,如果想同时继承两个类或者多个类,在Java语言中是无法实现的。同时在Java语言中使用太多的继承也会让一个class里的内容变得臃肿。所以在Java语言中能使用组合就尽量不使用继承。

2.6 多态的实现机制是什么

堕胎是面向对象程序设计中代码重用的一个重要机制,它表示同一个操作作用在不同对象时会有不同的语义,从而产生不同的结果。
例:
同样执行 ‘’ + " 操作:
2 + 1 结果为 3 实现整数相加
“2” + “1” 结果为 21 实现字符串拼接

多态主要有以下两种表现方式:

1)方法的重载(overload):重载是指同一个类中有多个同名方法,但这些方法有不同参数,因此在编译时可以选择调用哪个方法。
						 它是一种编译时多态,重载可以被看作一个类中的方法多态性。
						 
2)方法的覆盖(override):子类可以覆盖父类的方法,因此同样的方法会在子类与父类中有着不同的表现形式。
						 在Java语言中,,基类的引用变量不仅可以指向基类的实例对象,也可以指向其子类的实例对象。
						 接口的引用变量也可以指向其实现类的实例对象。

通过方法覆盖实现的多态也可以被称作运行时多态
例:

//父类方法
public class Father {
    public void normal() {
        System.out.println("父类方法");
    }
}

//子类方法
public class Son extends Father {
    public void normal() {//这里覆盖了父类的同名方法
        System.out.println("子类方法");
    }
}

//多态表现
public class Performance
{
    public static void main(String args[]) {
        Father father;//定义一个父类变量
        Son son;//定义一个子类变量
        father= new Son();//创建子类对象
        father.normal();//调用子类方法
        // son = new Father();子类的变量不能创建父类对象
        son = new Son();
        son.normal();
    }
}

运行结果是:
子类方法
子类方法

这就说明该变量是什么对象时,就调用什么方法,而与声明变量的类无关。


成员变量是无法实现多态的,成员变量的值取父类还是子类并不取决于创建对象的类型,而是却决于所定义变量的类型,这是在编译期确定的


总结:


Java提供了两种用于多态的机制,一种是编译时多态,一种是运行时多态。


编译时多态是通过方法的重载实现的。


运行时多态是通过方法的覆盖实现的。




2.7 重载和覆盖有什么区别

重载和覆盖是Java多态性的不同表现方式。

重载是在一个类中多态性的表现,是指一个类中定义了多个通过名方法,它们有不同的参数个数或者有不同的参数类型。

1)重载重载是通过不同方法参数来区分的,例如不同的参数个数,不同的参数类型或者不同的参数顺序。
2)不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载。
3)如果基类的访问类型为private,那么就不能在派生类对其进行重载;如果派生类也定义了一个同名函数,那么这只是一个新方法,而达不到重载的效果。

覆盖是指派生类函数覆盖基类函数。覆盖一个方法并对其重写,以达到不同作用。

1)派生类中的覆盖方法必须要和基类中被覆盖的方法有相同的函数名和参数。
2)派生类中的覆盖方法返回值必须和基类中被覆盖的方法的返回值相同。
3)派生类中的覆盖方法所抛出的异常必须和基类(或是其子类)中被覆盖的方法所抛出的异常一致。
4)基类中被覆盖的方法不能为private,否则其子类只是定义了一个方法,而并没有对基类的方法进行覆盖。


重载与覆盖的主要区别:

1)覆盖是子类与父类之间的关系,是垂直关系
   重载是同一个类中方法之间的关系,是水平关系
   
2)覆盖只能有一个方法或者是一对方法产生关系
   重载是多个方法之间的关系

3)覆盖要求参数列表相同
   重载要求参数列表不同

4)覆盖关系中,调用方法体是根据对象的类型来决定
   重载关系中是根据调用时的实参表和形参表来选择方法体的。

区别点

重载方法

重写(覆盖)方法

发生范围

同一个类

子类中

参数列表

必须修改

一定不能修改

返回类型

可修改

一定不能修改

异常

可修改

可以减少或删除,一定不能抛出新的或者更广的异常

访问修饰符

可修改

一定不能做更严格的限制(可以降低限制

发生阶段

编译期

运行期


2.8 抽象类(abstract class)与接口(interface)有什么异同

  一个类中包含抽象方法,那么这个类就是抽象类。在Java语言中可以把类或者类中某一些方法声明为abstract来表示一个类为抽象类(abstract只能用于修饰类或者方法,不能修饰属性)
  接口是指一个方法的集合,接口中所有方法都没有方法体,在Java语言中,接口是通过关键字interface来实现的。
  抽象类和接口都是支持抽象类定义的两种机制,二者具有很大的相似性,甚至有时候可以互换。但同时而这也有很大的区别。

抽象类与接口的相同点:

1) 都不能被实例化
2)接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法才能被实例化。

抽象类与接口的不同点:

1) Java8之前接口只能定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中的方法。
   抽象类可以有定义与实现,即其方法可以在抽象类中被实现。
   
2)接口需要实现(implement),一个类可以实现多个接口
   抽象类只能继承(extends),一个类只能继承一个抽象类

3)接口强调特定功能的实现,设计理念是 " has - a " 的关系。
   抽象类强调所属关系,设计理念是 " is - a " 的关系。

4)接口中定义的成员变量默认为 public static final,只能由静态的不能被修改的数据成员,而且必须给其赋初始值,其所有成员都是public,abstract的,而且只能被这两个关键词修饰。
   抽象类可以有自己的数据成员变量,也可以由非抽象的成员方法,而且丑类中的成员变量,默认为default,也可以定义为public、protected和private。这些成员变量可以在子类中重新被定义,也可以重新赋值。

5)接口被用于实现比较常用的功能,便于日后维护或者添加删除方法
   抽象类更倾向于充当公共类角色,不适用于日后对里面的代码进行修改


接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类可以有静态的main方法




2.9 内部类有哪些

  在Java语言中,可以把一个类定义到另外一个类的内部,在类里面的这个类就叫做内部类,外面的类叫做外部类。在这种情况下,这个内部类可以被看作外部类的一个成员。
  内部类可以分为很多种,主要有四种:

静态内部类:被声明为static的内部类,它可以不依赖于外部类实例而被实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类的静态成员和静态方法(包括私有类型)。

public class outerClass {
    //静态内部类
    static class innerClass {
    }
}

成员内部类:为非静态内部类,可以自由地引用外部类的属性和方法,无论这些属性和方法是静态的还是非静态的。但是当它与一个实例绑定在一起时,就不可以定义静态的属性和方法。只有在外部类被实例化后,这个内部类才能被实例化。

public class outerClass {
    //成员内部类(普通内部类)
    class innerClass {
    }
}

局部内部类:定义在一个代码块内的类,它的作用范围为其所在的代码块,是内部类中最少用到的类型。局部内部类和局部变量一样,不可以被public、protected、private以及static修饰,只能访问方法中被定义为final类型的局部变量。

public class outerClass {
    public void menberFunction() {
        //局部内部类
        class innerClass {
        }
    }
}

匿名内部类:匿名内部类是一种没有类名的内部类,不能使用关键字class、extends、implement,没有构造函数,它必须继承其他类或实现其他接口。匿名内部类会是代码更加紧凑,但却会使可读性下降。它一般应用在GUI编程中实现事件处理等。

public class MyFrame extends Frame {
    public MyFrame() {
        //匿名内部类
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e){
                dispose();
                System.exit(0);
            }
        });
    }
}

在使用匿名内部类时,需要牢记以下原则:

1)匿名内部类不能有构造函数
2)匿名内部类不能定义静态成员、方法和类
3)匿名内部类不能是public、protected、private、static
4)只能创建匿名内部类的一个实例
5)一个匿名内部类一定是在new的后面,这个匿名内部类一定继承一个父类或者实现一个接口
6)因为匿名内部类为局部内部类,所以局部内部类的局限对其生效


2.10 this与super有什么区别

this是用来指向当前实例对象,它的一个非常重要的作用就是用来区分对象的成员变量和方法的形参。当一个方法的形参与成员变量的名字相同时,就会覆盖成员变量
示例:

class People {
    String name;

    public People(String name) {
        this.name = name;
    }
}

super可以用来访问父类的方法或成员变量。当子类的方法或成员变量与父类有相同名字是也会覆盖父类的方法或成员变量,要想能够访问父类的方法或成员变量只能用super关键字访问。
示例:

class Hobby{
    String name;
    void value() {
       name = "游戏";
    }
}
  
class Game extends Hobby{
    String name;
    void value() {
    name = "LOL";
    super.value();      //调用父类的方法
    System.out.println(name);
    System.out.println(super.name);
    }
  
    public static void main(String[] args) {
       Game g=new Game();
       c.value();
       }
}

结果:
LOL
游戏





注:

此文来源于《Java程序员面试笔试宝典》一书

仅作为本人学习过程的记录

填写原创是因为找不到相关链接

如有不妥请联系本人,会立即删除

此书对于我这种小白来说非常有用,讲解详细,知识点全面,目前正在根据此书学习,陆续会记录更多知识点。