摘要:该篇文章主要是总结了一下面试过程中关于接口、抽象类、面向对象的四大特性的知识点。
前言:接口、抽象类、面向对象的四大特性在面试的过程中属于基础中的基础,是属于入门级别的题目,这些内容如果回答不上,基本上你的面试就会直接GG。建议熟练掌握,特别是一些容易混淆的概念。
抽象类和接口
抽象方法
在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:
1 |
|
抽象方法必须使用abstract关键字进行修饰。
抽象类
如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中无具体实现的方法,所以不能用抽象类创建对象。
在《JAVA编程思想》一书中,将抽象类定义为 “包含抽象方法的类” ,但是如果一个类不包含抽象方法,只是用abstract修饰的话也是抽象类。也就是说抽象类不一定必须含有抽象方法。例如下面的两个类,都是抽象类:
1 |
|
总结:
包含抽象方法的类称为抽象类(但是抽象类不一定要拥有抽象方法),但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:
- 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
- 抽象类不能用来创建对象;
- 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。
接口
接口中可以含有变量和方法。
接口中的变量会被隐式地指定为 public static final 变量(并且只能是 public static final变量,用 private 修饰会报编译错误)。
方法会被隐式地指定为 public abstract 方法且只能是 public abstract 方法(用其他关键字,比如 private、protected、static、 final 等修饰会报编译错误),并且接口中所有的方法不能有具体的实现(Java8以后,接口中可以提供方法的默认实现),也就是说,接口中的方法必须都是抽象方法。
从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加”抽象”,并且一般情况下不在接口中定义变量。在 Java 中,定一个接口如下所示:
1 |
|
抽象类和接口的区别
1、语法层面上的区别
- 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract方法;
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
- 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
2、设计层面上的区别
抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。也就是说接口中的方法,必须是这一类事物共有的特征,不能拥有属于自己的个性特征。但是抽象类拥有这一类事物共有的特征,并且还拥有自己特有的属性、方法。举个例子:动物共有的特征:交流、进食。但是每种动物又有用自己的特征,比如鸟会飞、鱼会游泳、壁虎会爬。所以如果以动物维度进行接口设计的话,则这里只能吧交流、进食等所有动物都 共有 的特征设计成接口中的方法,如果是某一类动物特有的特征,则只能设计成 更小的接口 或者 抽象方法;
面向对象的四大特性:抽象、封装、继承、多态
抽象
抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
封装
通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
继承
继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为 父类(超类、基类);得到继承信息的类被称为 子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段(桥梁模式)。
多态
多态性是指允许不同类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。 方法重载(overload) 实现的是 编译时的多态性(也称为前绑定),而 方法重写(override) 实现的是 运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:
- 方法重写(子类继承父类并重写父类中已有的或抽象的方法)。
- 对象造型(用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
总结:
在同一个方法中,这种由于参数类型不同而导致执行效果各异的现象就是多态。
Java实现多态有三个必要条件:继承、重写、向上转型。
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
- 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。
instanceof可以判断一个对象是否为某个类(或接口)的实例或者子类实例。
语法格式:对象(或者对象引用变量) instanceof 类(或接口)JAVA运行过程:编译,类的加载,类的执行。
多态机制遵循的原则概括为:当超类对象引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
只有方法具有多态性,变量不具有多态性。
以上概念,可以参考下面的代码,进行理解
1 | class A{ |
问题时刻
1 |
|
请给出上面代码的运行结果,并思考上面代码存在的问题。
答:
运行结果为:
Father执行……
Son执行……
存在的问题:Son类实际上是重载了show方法,而不是重写。Son类没有遵循里氏替换原则。
- 本文作者: th3ee9ine
- 本文链接: https://www.blog.ajie39.top/2021/05/05/面试基础题之《面向对象》/
- 版权声明: 本博客所有文章除特别声明外,均采用 LICENSE 下的许可协议。转载请注明出处!