参考Java程序员面试笔试宝典:
目录
8.抽象类(abstract class)与接口(interface)有什么异同
1.面向对象与面向过程有何区别
1)出发点不同。面向对象强调把问题域的要领映射到对象及对象之间的接口上,面向过程强调过程的抽象化和模块化。
2)层次逻辑关系不同。面向对象用类的层次结构来体现类之间的继承与发展,面向过程用模块的层次结构概括模块或模块间的关系与功能。
3)数据处理方式与控制程序方式不同。面向对象将数据和代码封装为一个整体,事件驱动;面向过程直接通过程序处理数据。
4)分析设计与编码转换方式不同。面向对象平滑过程,无缝连接;面向过程有缝连接。
之后补充在网上看到的一个问题:面向过程是否就比面向对象性能高?
面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。
这个并不是根本原因,面向过程也需要分配内存,计算内存偏移量,Java性能差的主要原因并不是因为它是面向对象语言,而是Java是半编译语言,最终的执行代码并不是可以直接被CPU执行的二进制机械码。
而面向过程语言大多都是直接编译成机械码在电脑上执行,并且其它一些面向过程的脚本语言性能也并不一定比Java好。
此问题原链接:https://github.com/Snailclimb/JavaGuide/issues/431
2.面向对象的特征
1)抽象:忽略与当前目标无关的方面,只注意与目标有关的方面。过程抽象、数据抽象。
2)继承:对象一个新类可从现有类中派生,新类继承原始类的特性。
3)封装:将客观事物抽象成类,每个类对自身数据和方法进行保护。
4)多态:允许不同类的对象对同一消息做出响应。参数化多态、包含多态。
3.面向对象开发有何优点
1)较高的开发效率
2)保护软件的鲁棒性,有很高的重用性
3)保证软件的高可维护性,可读性好,拥有成熟的设计模式
4.什么是继承
通过继承,子类可以使用父类中的一些成员变量与方法,提高代码复用性,提高开发效率。
被继承类叫基类、父类,继承类叫派生类、子类。通过extends关键字实现。
继承的特性:
1)子类至多只能有一个父类,但可以通过实现多个接口实现多重继承。
2)子类只能继承父类的非私有成员变量与方法。
3)当子类中定义的成员变量与方法与父类重名,子类会覆盖该变量或方法,而不会继承。
5.组合与继承有什么区别
组合:在新类里创建原有类的对象,重复利用已有类的功能。 has -a
继承:根据其他类的实现定义一个类的实现。 is-a
选择时遵循的原则:
1)除非两个类之间是“is-a”的关系,否则不要轻易使用继承。过多使用继承会破坏代码可维护性,当父类修改时,会影响继承的子类,增加程序的维护难度与成本。
2)不要为了实现多态而使用继承。类之间没有“is-a”关系,可通过实现接口与组合的方式达到相同目的,且具有跟好的扩展性。能使用组合尽量不要使用继承。
6.多态的实现机制是什么
当同一个操作作用在不同对象时,会有不同的语义,产生不同的结果。“+”可以是整数相加,可以是字符串的连接
多态有两种表现方式:
1)方法的重载:同一个类有多个同名方法,但有着不同的参数,根据调用参数确定使用哪个方法,是一种编译时多态,可看作一个类中的方法多态性。
2)方法的覆盖:子类可以覆盖父类的方法,同样的方法在父类与子类中有着不同的表现形式。运行时多态。
只有类中的方法才有多态的概念,类中成员变量没有多态的概念,即成员变量无法实现多态。
问:java提供了哪两种用于多态的机制?
答:编译时多态和运行时多态。编译时多态通过方法的重载实现,运行时多态通过方法的覆盖(子类覆盖父类方法)实现的。
7.重载和覆盖有什么区别
重载(overload)和覆盖(override)是Java多态性的不同表现形式。
重载是指在一个类中定义多个同名方法,但他们有不同的参数个数或参数类型。
使用重载需注意:
1)重载通过不同的方法参数区分,包括参数个数、参数类型、参数顺序
2)不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载。
3)对于继承,若基类方法访问权限为private,则派生类无法对其方法进行重载;若方法同名,只是一个新函数方法,没有重载效果。
覆盖指派生类函数覆盖基类函数。覆盖一个方法并对其重写,达到不同的效果。
1)覆盖方法必须和被覆盖方法有相同的函数名和参数,且返回值相同,抛出异常一致。
2)被覆盖方法不能为private,否则子类只是定义一个方法,没有覆盖。
两者区别:
1)覆盖是子类和父类关系,是垂直关系;重载是一个类中方法之间的关系,是水平关系。
2)覆盖由成对的方法产生关系;重载是多个方法之间的关系。
3)覆盖要求参数列表相同;重载要求参数列表不同。
4)覆盖关系调用方法是根据对象的类型来决定;重载是根据调用时的实参表和形参表来选择方法体的。
8.抽象类(abstract class)与接口(interface)有什么异同
同:
1)都不能被实例化
2)接口的实现类和抽象类的子类都必须实现了接口和抽象类中的方法才能够被实例化。
异:
1)Java8之前,接口只有定义,方法不能在接口中实现;而抽象类可以有定义和实现,方法可以在抽象类中实现
2)接口需要实现(implements),抽象类只能继承(extends)。一个类可以实现多个接口,但一个类只能继承一个抽象类,使用接口可间接达到多重继承的目的。
3)接口强调特定功能实现,“has-a”;抽象类强调所属关系,“is-a”。
4)接口中成员变量默认public static final,必须赋初值,所有方法都是public,abstract。
抽象类可以有自己的成员变量,默认default(本包可见),可定义private,protected,public,可在子类中重新定义、重新赋值;抽象类中方法有abstract修饰,不能用private、static、synchronized、native修饰,方法必须以分号结尾,不带花括号{}。
5)接口用于实现比较常用的功能,便于日后维护或添加和删除方法;抽象类倾向充当公共类角色,不适合日后对其代码进行修改。
9.内部类有哪些
java中,把一个类定义到另外一个类的内部,在类里面这个类叫内部类,外面的类叫外部类,内部类可看作外部类的一个成员,与类的属性和方法类似。
内部类主要有:
静态内部类(static inner class)
成员内部类(member inner class)
局部内部类(local inner class)
匿名内部类(anonymous inner class)
定义:
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
class outerClass{
static class innerClass{} //静态内部类
}
class outerClass{
class innerClass{} //成员内部类
}
class outerClass{
public void menberFunction(){
class innerClass{} //局部内部类
}
}
public class MyFrame extends Frame { //外部类
public MyFrame() {
addWindowListener(new WindowAdapter() { //匿名内部类
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
}
}
1)静态内部类指被声明为static的内部类,可不依赖于外部类实例而被实例化,而通常内部类需要在外部类实例化后才能实例化。静态内部类不能和外部类名字相同,不能访问外部类普通成员变量,只能访问外部类的静态成员变量和静态方法(包括私有类型)
2)成员内部类为非静态内部类,就是静态内部类去掉了static关键字,它可自由引用外部类属性和方法,无论静态还是非静态。不可定义静态属性和方法,只有外部类实例化,内部类才能实例化。
3)局部内部类指定义在一个代码块内的类,作用范围为所在代码块,在内部类中最少使用。它不能被public、private、protected和static修饰,只能访问方法中定义为final的局部变量。对一成员类,将其移入外部类的实例方法或实例初始化代码就成为局部内部类。
4)匿名内部类是没有类名的内部类,不适应关键字class、extends、implements,没有构造函数,必须继承其他类或实现其他接口。好处是代码简介紧凑,但易读性下降。一般用于GUI(图形用户界面)实现事件处理。匿名内部类使用原则:
1.不能有构造函数
2.不能定义静态成员、方法、类
3.不能有修饰符public、protected、private、static
4.只能创建匿名内部类的一个实例
5.一定是在new后面,必须继承一个父类或实现一个接口
6.匿名内部类为局部内部类,局部内部类所有限制都对其生效
10.如何获取父类类名
getClass().getName()
如何在子类中得到父类名字?
getClass().getSuperclass().getName()
11.this和super有何区别
this用来指向当前实例对象,最重要的作用就是用来区分对象的成员变量和方法的形参(当一个方法的形参与成员变量的名字相同,就会覆盖成员变量),通常格式为this.成员变量=形参
super用来访问父类的成员变量和方法。当子类存在和父类相同方法或变量,就会覆盖,访问父类方法或变量只能用super关键字。
当子类构造函数需要显式调用父类构造函数,super()必须为构造函数第一条语句。