JAVA面试题 ——— JAVA基础知识篇(三)
1、请你说一下什么是面向对象?
JAVA是面向对象的编程语言,不同于C语言是面向过程的。对于面向对象和面向过程的区别,举一个简单的例子说明一下(我们以洗衣机洗衣服为例):
- 面向过程:面向过程的编程方式,程序会将要完成的某一个任务拆解成一系列的小步骤(函数),如:
- 打开洗衣机:
- 放入要洗的衣服:
- 放入洗衣粉:
- 清洗:
- 烘干:
- 面向对象:面向对象的编程方式,程序会将要完成的洗衣机洗衣服的任务超分成如下两个对象:
- 人():在洗衣机洗衣服这个过程任务中有三个作用,分别是、、
- 洗衣机():在洗衣机洗衣服这个过程中有两个作用,分别是:、。
从上面这个例子能看出,面向过程的编程方式比较直接且高效,而面向对象的编程方式更容易复用、扩展和维护。
2、请你简述一下面向对象的三个基本特征?
- 继承:继承是JAVA中面向对象最显著的一个特征,继承是从已有的类中派生出新的类,新的类吸收已有的属性、行为,并扩展新的能力。JAVA中不支持多继承,但是接口可以支持多实现。
- 封装:将同一类事物的特征和功能包装在一起,只对外暴露需要调用的接口。封装也称为信息的隐藏,在JAVA中接口是体现封装最常用的方法,在接口中我们没有任何功能的实现(具体实现都交给实现类),只是定义了一系列抽象的方法声明于外部调用。
- 多态:封装和继承都是为多态来服务的,多态是指同一个行为具有不同的表现形式。在JAVA中方法的重载和重写是实现多态的两种方式。
- 重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载。方法重载体现了编译时的多态性。
- 重写发生在子类与父类之间,重写要求子类被重写方法有相同的返回类型和相同的参数列表,重载对返回类型没有特殊的要求。方法重写体现了运行时多态性。
多态的三要素:继承、重写、父类指向子类引用。
3、请你讲讲抽象类和接口有什么区别?
- 继承方面:
- 抽象类只能单继承,而接口可以多实现
- 成员属性方面:
- 抽象类中可以有普通属性,也可以有常量
- 接口中的成员变量全部默认是常量,使用修饰,这个可以省略不写
- 代码块方面:
- 抽象类可以含初始化块,接口不能含初始化块
- 构造函数方面:
- 抽象类可以有构造函数,但是这里的构造函数不是用来创建对象的,而是用来被实现类调用进行初始化操作的;
- 方法方面:
- 接口在JDK1.8以后可以定义抽象方法(无方法体)、修饰的默认方法(有方法体)、修饰的静态方法(有方法体),JDK1.8以前只能有抽象方法
- 抽象类中除了静态方法和抽象方法外还可以有普通方法
二者相同之处
- 接口与抽象类都不能被实例化,需要被其他进行实现或者继承
- 接口与抽象类里面都能包含抽象方法,实现接口或者继承抽象类的子类都必须实现这些方法 java项目基础讲解
4、请判断当一个对象被当作参数传递给一个方法后,此方法可以改变这个对象的属性,并可返回变化后的结果,那么这里值传递还是引用传递?
是。JAVA编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中的时候,参数的值就是该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
JAVA中只有值传递,基本类型传递的是值的副本,引用类型传递的是引用的副本。
5、请你说一下方法重载和方法重写的区别?
- 重载:方法重载发生在同一个类中,重载的方法之间方法民必须相同,参数列表不同(参数的类型、参数的个数),方法的返回值和访问修饰符可以不同,发生在(方法重载实现了编译时的多态)。
- 重写:方法重写发生在子父类中,子类重写父类的方法,方法名称必须相同,参数列表也必须相同,方法的返回值小于等于父类方法的返回值,子类方法访问修饰符应大于等于父类方法访问修饰符(如果父类方法修饰符为,则子类就无法重写了)。
6、请你说一下List接口和Set接口的区别?
- :有序、可重复集合。按照对象插入的顺序保存数据,允许多个元素对象,可以使用迭代器遍历,也可以使用方法获取指定下标元素。
- :无序、不可重复集合只允许有一个对象元素,取元素的时候,只能使用迭代器逐一遍历
- :key-value 键值对的形式的集合,添加或获取元素的时候,需要通过key来检索到value。
Collection集合体系结构图:
7、请你说一下JAVA中的IO流?以及他们的分类和作用?
IO流的分类?
- 按照数据流的方向的不同,可以划分为和。
- 按照处理数据单位的不同,可以划分为和。
- 按照流的实现功能的不同,可以划分为和。
JAVA的IO流共涉及40多个类,这40多个类都是从如下4个抽象类基类派生而来的:
- :所有的输入流的基类,前者是字节输入流,后者是字符输入流
- :所有的输出流的基类,前者是字节输出流,后者是字符输出流
按照操作方式分类结构图:
这里我们重点提一下和:
转换流:实现字节流和字符流之间的转换
- :将一个字节输入流转换为字符输入流
- :将一个字符输出流转换为字节流
缓冲流:增加缓冲功能,避免频繁读写硬盘
如:、、、
我们来看一个转换流和缓冲流配合的案例:
流使用结束后记得关闭流,关闭的顺序遵循如下几个规则:
- 先开后关,先开的输入流,再开的输出流,通过读取输入流写入的输出流,那么应该先关输出流,再关输入流,但是一般关闭输入输出流操作都是再读写完成后的中执行的,所以即使先关输入流,再关输出流也不会任何问题,因为读写操作没有进行了。
- 先关外层,再关内层,如包装了一个,那么先关,再关。但是要注意的是由于一般处理流持有节点流引用,处理流一般都会再自己的方法中去关闭节点流,因此我们只需要关闭外层的处理流即可,如果多此一举的关闭节点流反而会报错。如包装了,我们只要关闭即可。
- 只关处理流,不关节点流,原因同上。
8、请你说一说BIO、NIO、AIO有什么区别?
在对比这三者的区别之前,先了解一下什么是同步/异步、阻塞/非阻塞:
- 同步:一个任务的完成之前不能做其他操作,必须等待(相当于在打电话)
- 异步:一个任务的完成之前,可以进行其他操作(相当于在聊)
- 阻塞:是相对于CPU来说的,挂起当前线程,不能做其他操作只能等待
- 非阻塞:无须挂起当前线程,也可以去执行其他操作
BIO、NIO、AIO的区别
- BIO:同步阻塞:就是我们平常使用的传统IO,它的特点是模式简单使用方便,并发处理能力低。每当有一个客户端向服务器发起请求的时候,服务器都要启动一个线程。
同步:无论客户端是否响应,线程必须一直等待
可见当有多个客户端发出请求的时候,服务器需要启动等量的线程,而且当客户端没有响应的时候,线程也必须一直等待,长期下来需要大量的线程且线程利用率低,会造成浪费。
- NIO:同步非阻塞,是传统IO的升级,客户端和服务器通过Channel(通道)通讯,实现了多路复用。服务器用一个线程来处理多个请求,客户端发送的请求会注册到多路复用器(selector选择器)上,有IO请求的客户端分配线程处理。
- AIO:异步非阻塞,是NIO的升级,也叫NIO2,实现了异步非阻塞IO,异步IO的操作基于事件和回调机制。客户端发送的请求先交给操作系统处理,OS处理后再通知线程。
9、请你说一下ERROR和Exception区别是什么?
Error和Exception都是Throwable的子类,用于表示程序出现了不正常的情况。区别在于:
- ERROR是程序错误,通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA应用程序也不应对这类错误进行捕获,一旦这类错误发生,通常应用程序会被终止,仅仅靠应用程序本身无法恢复;
- Exception是程序异常,是可以在应用程序中进行捕获处理的,是一种设计或实现问题,也就是说,它表示如果线程运行正常,从不会发生的情况。
10、请问try-catch-finally中,如果catch中return了,finally还会执行嘛?
答案:会执行,在之前执行。
代码如下:
总结:
- 不管有没有异常,中的代码都会执行。
- 当、中有的时候,中的代码依然会继续执行。
- 如果的数据是引用数据类型,而在中对该引用数据类型的属性值的改变起作用,中的语句返回的就算在中改变后的该属性的值。
- 代码中最好不要包含,程序会提前退出,也就是说返回的值不是或中的值。
- 是在后面的表达式运算之后执行的,此时并没有返回运算之后的值,不管对该值做任何的改变,返回的值都不会改变,依然返回保存起来的值。也就是说方法的返回值是在finally运算之前就确定了的。
11、请你说一下:String str=new String(“abc”)创建了几个字符串对象?
答案:1个或者两个
- 如果字符串常量池中已经有存在,这种情况只需要新建一个对象,否则就需要新建2个对象。
- 当字符串常量池没有,此时会创建如下两个对象:
- 一个是字符串字面量所对应的、驻留(intern)在一个全局共享的字符串常量池中的实例,此时该实例也是在堆中,字符串常量池中只存放引用。
- 另一个是通过创建并初始化的,内容与相同的实例,也是在堆中。
总结:如果字符串常量池intern中没有对应的那么就需要在字符串常量池新建,然后再在堆上new一个对象。
12、JAVA中的128陷阱有了解过吗?
先来看一个例子:
为什么会出现这种情况呢?
- 我们都知道是基本类型的的包装类型
- 在JAVA设计之初,设计者认为,开发者可能经常用到的数字范围都在100以内,而每次使用这些数字的包装类型都要开辟新空间的话,可能会占用大量的资源。
- 因此它们规定在之间的类型的变量,直接指向常量池中的缓存地址,不再使用new去开辟出新的空间。
执行,相当于执行:,基本类型自动转换为包装类的过程称为,自动装箱(autoboxing)。
这也是出现上述代码两次比较结果不一样的原因!下面我们看下源码体会下:
在中引入了来缓存一定范围的值,默认情况下范围为:。
因此,上述代码中的命中了,所以a和b是相同对象,而128没有命中,所以c和d是不同对象。
那么,如果想要正确比较c与d的话,就需要拆箱比较,即在变量后加方法:
包括以下的类型也是一样的:
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/h6javajc/1486.html