2018最新 java 面试题总结(一)

Q:面向对象编程的四大特性及其含义?

封装:将某事物的属性和行为包装到对象中,构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,并且尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。通俗点即隐藏信息 提供使用接口给别人使用,不让别人直接操作属性或方法

继承:子类继承父类,不仅可以有父类原有的方法和属性,也可以增加自己的或者重写父类的方法及属性

多态:多态的概念即“一个接口,多个方法” ,允许不同类的对象对同一消息做出各自的响应

抽象 :面向对象的领域一切都是对象,同时所有的对象都是通过类来描述的,但是并不是所有的类都是来描述对象的。如果一个类没有足够的信息来描述一个具体的对象,而需要其他具体的类来支撑它,那么这样的类我们称它为抽象类。比如new Animal(),我们都知道这个是产生一个动物Animal对象,但是这个Animal具体长成什么样子我们并不知道,它没有一个具体动物的概念,所以他就是一个抽象类,需要一个具体的动物,如狗、猫来对它进行特定的描述,我们才知道它长成啥样。抽象类提供了继承的概念,它的出发点就是为了继承,否则它没有存在的任何意义。所以说定义的抽象类一定是用来继承的,同时在一个以抽象类为节点的继承关系等级链中,叶子节点一定是具体的实现类。

接口和抽象类的区别:

(1)相同点

A,两者都是抽象类,都不能实例化。

B,interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法。 

(2)不同点

A,interface实现,要用implements,而abstract class的实现,要用extends。

 B,一个类可以实现多个interface,但一个类只能继承一个abstract class。

 C,interface强调特定功能的实现,而abstract class强调所属关系。 

D,尽管interface实现类及abstrct class的子类都必须要实现相应的抽象方法,但实现的形式不同。

 E,interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能声明private及protected的方法,不能定义方法体,也不能声明实例变量。

Q:String、StringBuffer和StringBuilder的区别?

String是字符串常量,而StringBuffer、StringBuilder都是字符串变量,即String对象一创建后不可更改,而后两者的对象是可更改的:

StringBuffer是线程安全的,而StringBuilder是非线程安全的,这是由于StringBuffer对方法加了同步锁或者对调用的方法加了同步锁

String更适用于少量的字符串操作的情况,StringBuilder适用于单线程下在字符缓冲区进行大量操作的情况,StringBuffer适用于多线程下在字符缓冲区进行大量操作的情况

Q:String a=””和String a=new String(“”)的的关系和异同?

通过String a=””直接赋值的方式得到的是一个字符串常量,存在于常量池;注意,相同内容的字符串在常量池中只有一个,即如果池已包含内容相等的字符串会返回池中的字符串,反之会将该字符串放入池中

通过new String(“”)创建的字符串不是常量是实例对象,会在内存开辟空间并存放数据,且每个实例对象都有自己的地址空间

引申:对于用String a=””和String a=new String(“”)两种方式定义的字符串,判断使用equals()、”==”比较结果是什么

Q:Object的equal()和==的区别?

1.==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同

2.==是指对内存地址进行比较 equals()是对字符串的内容进行比较

3.==指引用是否相同 equals()指的是值是否相同  

《2018最新 java 面试题总结(一)》

Q:装箱、拆箱什么含义?

装箱就是自动将基本数据类型转换为包装器类型,拆箱就是自动将包装器类型转换为基本数据类型

Integer i = 10;  //装箱

int n = i;   //拆箱  

Q:int和Integer的区别?

Integer是int的包装类,int则是java的一种基本数据类型

Integer变量必须实例化后才能使用,而int变量不需要

Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值

Integer的默认值是null,int的默认值是0

Q:遇见过哪些运行时异常?异常处理机制知道哪些?

对Throwable异常进行分类说明每种异常的特点和常见问题,简述几种常见异常处理机制,详见Java基础之异常机制

(1) Throwable继承层次结构,可见分成两大类Error和Exception:

Error(错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题;发生于虚拟机自身、或者在虚拟机试图执行应用时,如Virtual MachineError(Java虚拟机运行错误)、NoClassDefFoundError(类定义错误);属于不可查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。

Exception(异常):指程序有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类:

RuntimeException(运行时异常):由程序自身的问题导致产生的异常;如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常);属于不可查异常。

非运行时异常:由程序外部的问题引起的异常;除了RuntimeException以外的异常,如FileNotFoundException(文件不存在异常);属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。

《2018最新 java 面试题总结(一)》

(2)常见的异常处理机制有:

捕捉异常:由系统自动抛出异常,即try捕获异常->catch处理异常->finally 最终处理

抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。配合throws声明抛出的异常和throw抛出异常

自定义异常:继承Execption类或其子类

Q:什么是反射,有什么作用和应用?Java基础之泛型&反射

我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

引申:是否在项目中使用过反射机制,有什么优缺点

反射提供了一种运行期获取对象元信息的手段。写框架代码用的比较多,因为需要运行时动态获取和操作对象的属性和方法。尽量少用反射,会有性能开销,大多数场景下可以用设计模式代替。

举个具体应用场景:你用第三方jar,比如spring/imageload,你可以在配置文件修改各种参数,但你不可能会去直接修改里面的代码吧,这些代码就是获取配置文件里的数据再通过反射来操作,降低耦合。

Q:什么是内部类?有什么作用?静态内部类和非静态内部类的区别?

内部类就是定义在另外一个类里面的类。它隐藏在外部类中,封装性更强,不允许除外部类外的其他类访问它;但它可直接访问外部类的成员。静态内部类和非静态内部类的区别有:

静态内部类是指被声明为static的内部类,可不依赖外部类实例化;而非静态内部类需要通过生成外部类来间接生成。

静态内部类只能访问外部类的静态成员变量和静态方法,而非静态内部类由于持有对外部类的引用,可以访问外部类的所用成员

静态内部类和非静态内部类的区别

Q:Java中的final关键字

方法前面加上final关键字,代表这个方法不可以被子类的方法重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为final。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。

你不能够对final变量再次赋值。本地变量必须在声明时赋值。在匿名类中所有变量都必须是final变量。 

final关键字的好处:

final关键字提高了性能。JVM和Java应用都会缓存final变量。

final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。

使用final关键字,JVM会对方法、变量及类进行优化。  

Q:重写和重载的区别?

参考回答:重写表示子类重写父类的方法;重载表示有多个同名函数同时存在,区别在于有不同的参数个数或类型

引申:谈谈动态分派和静态分派

Q:抽象类和接口的异同?

使用上的区别:一个类只能继承一个抽象类却可以实现多个接口

设计上的区别:接口是对行为的抽象,无需有子类的前提,是自上而下的设计理念;抽象类是对类的抽象,建立于相似子类之上,是自下而上的设计理念

Q:为什么匿名内部类中使用局部变量要用final修饰?

一方面,由于方法中的局部变量的生命周期很短,

一旦方法结束变量就要被销毁,为了保证在内部类中能找到外部局部变量,通过final关键字可得到一个外部变量的引用;

另一方面,通过final关键字也不会在内部类去做修改该变量的值,保护了数据的一致性。

匿名内部类

Q:Object有哪些公有方法?

equals(): 和==作用相似

hashCode():用于哈希查找,重写了equals()一般都要重写该方法

getClass(): 获取Class对象

wait():让当前线程进入等待状态,并释放它所持有的锁

notify()&notifyAll(): 唤醒一个(所有)正处于等待状态的线程

toString():转换成字符串

引申:equals()和==的不同、在synchronized 同步代码块里wait()和notify()&notifyAll()如何配合、hashCode()和equals()的关系、获取Class对象还有什么方法

Q:Java集合框架中有哪些类?都有什么特点

可将Java集合框架大致可分为Set、List、Queue 和Map四种体系

Set:代表无序、不可重复的集合,常见的类如HashSet、TreeSet

List:代表有序、可重复的集合,常见的类如动态数组ArrayList、双向链表LinkedList、可变数组Vector

Map:无序  ,不可重复的集合 ,代表具有映射关系的集合,常见的类如HashMap、LinkedHashMap、TreeMap

Queue:代表一种队列集合

有序,无序:比如:‘zs’,‘zs’ 这两个 是不同的人是同一个名字,没顺序你是无法判断是谁的list他是有顺序的,所以你只要知道他们的顺序就完全可以判断是哪个人了,

可重复:key和value都可以重复,  不可重复:key不可以重复,value可以重复

Q:集合、数组、泛型的关系,并比较

(1)集合和数组的区别:

数组元素可以是基本类型,也可以是对象;数组长度限定;数组只能存储一种类型的数据元素

集合元素只能是对象;集合长度可变;集合可存储不同种的数据元素

(2)泛型相比与集合的好处在于它安全简单。具体体现在提供编译时的强类型检查,而不用等到运行;可避免类类型强制转换

Java 泛型

Q:ArrayList和LinkList的区别?

ArrayList的底层结构是数组,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。

LinkedList是用链表结构存储数据,增删速度快;是一个双向循环链表,也可以被当作堆栈、队列或双端队列

Vector与ArrayList一样,也是通过数组实现的

Q:ArrayList和Vector的区别?

安全,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList;

Vector使用了synchronized关键字,是线程安全的,比ArrayList开销更大,访问更慢;默认初始容量为10,默认每次扩容为原来的2倍,可通过capacityIncrement属性设置

ArrayList在内存不够时默认是扩展50% + 1个,Vector是默认扩展1倍。                                                                                                    Vector提供indexOf(obj, start)接口,ArrayList没有。                                                                                                                                Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。 

Q:HashSet和TreeSet的区别?

HashSet不能保证元素的排列顺序;使用Hash算法来存储集合中的元素,有良好的存取和查找性能;通过equal()判断两个元素是否相等,并两个元素的hashCode()返回值也相等

TreeSet是SortedSet接口的实现类,根据元素实际值的大小进行排序;采用红黑树的数据结构来存储集合元素;支持两种排序方法:自然排序(默认情况)和定制排序。前者通过实现Comparable接口中的compareTo()比较两个元素之间大小关系,然后按升序排列;后者通过实现Comparator接口中的compare()比较两个元素之间大小关系,实现定制排列

Q:HashMap和Hashtable的区别?

HashMap基于AbstractMap类,实现了Map、Cloneable(能被克隆)、Serializable(支持序列化)接口;非线程安全;允许存在一个为null的key和任意个为null的value;采用链表散列的数据结构,即数组和链表的结合;初始容量为16,填充因子默认为0.75,扩容时是当前容量翻倍,即2 capacity

Hashtable基于Map接口和Dictionary类;线程安全,开销比HashMap大,如果多线程访问一个Map对象,使用Hashtable更好;不允许使用null作为key和value;底层基于哈希表结构;初始容量为11,填充因子默认为0.75,扩容时是容量翻倍+1,即2capacity+1

Q:HashMap在put、get元素的过程?体现了什么数据结构?

向HashMap中put元素时,首先判断key是否为空,为空则直接调用putForNullKey(),不为空则计算key的hash值得到该元素在数组中的下标值;如果数组在该位置处没有元素,就直接保存;如果有,还要比较是否存在相同的key,存在的话就覆盖原来key的value,否则将该元素保存在链头,先保存的在链尾。

从Hashmap中get元素时,计算key的hash值找到在数组中的对应的下标值,返回该key对应的value即可,如果有冲突就遍历该位置链表寻找key相同的元素并返回对应的value

由此可看出HashMap采用链表散列的数据结构,即数组和链表的结合,在Java8后又结合了红黑树,当链表元素超过8个将链表转换为红黑树

Q:HashMap是如何扩容的?如何避免扩容?

HashMap几个默认值,初始容量为16、填充因子默认为0.75、扩容时容量翻倍。也就是说当HashMap中元素个数超过16*0.75=12时会把数组的大小扩展为2*16=32,然后重新计算每个元素在数组中的位置.

由于每次扩容还需要重新计算元素Hash值,损耗性能,所以建议在使用HashMap时,最好先估算Map的大小,设置初始值,避免频繁扩容

Q:hashcode()的作用,与equal()有什么区别?

hashCode()用于计算对象的Hash值,确认对象在散列存储结构中的存储地址。和equal()的区别:

equals()比较两个对象的地址值是否相等 ;hashCode()得到的是对象的存储位置,可能不同对象会得到相同值

有两个对象,若equals()相等,则hashcode()一定相等;hashcode()不等,则equals()一定不相等;hashcode()相等,equals()可能相等、可能不等

使用equals()比较两个对象是否相等效率较低,最快办法是先用hashCode()比较,如果hashCode()不相等,则这两个对象肯定不相等;如果hashCode()相等,此时再用equal()比较,如果equal()也相等,则这两个对象的确相等,反之并发

Q:同步和非同步、阻塞和非阻塞,并发,并行的概念

同步和异步体现的是消息的通知机制:所谓同步,方法A调用方法B后必须等到方法B返回结果才能继续后面的操作;所谓异步,方法A调用方法B后可让方法B在调用结束后通过回调等方式通知方法A

阻塞和非阻塞:侧重于等待消息时的状态:所谓阻塞,就是在结果返回之前让当前线程挂起;所谓非阻塞,就是在等待时可做其他事情,通过轮询去询问是否已返回结果

并发,并行 :并发是指一个时间段内,有几个程序都在同一个CPU上运行,但任意一个时刻点上只有一个程序在处理机上运行。并行是指一个时间段内,有几个程序都在几个CPU上运行,任意一个时刻点上,有多个程序在同时运行,并且多道程序之间互不干扰。 两者区别如下图

Q:Thread的join()有什么作用?

参考回答:Thread的join()的含义是等待该线程终止,即将挂起调用线程的执行,直到被调用的对象完成它的执行。比如存在两个线程t1和t2,下述代码表示先启动t1,直到t1的任务结束,才轮到t2启动。

t1.start();

t1.join();

t2.start();

Q:线程的有哪些状态?

参考回答:在任意一个时间点,一个线程只能有且只有其中的一种状态:

线程状态

1.新建(New)new语句创建的线程对象处于新建状态,此时它和其他java对象一样,仅被分配了内存。

2.等待(Runable)当线程在new之后,并且在调用start方法前,线程处于等待状态。

3.就绪(Waiting)当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态。处于这个状态的线程位于Java虚拟机的可运行池中,等待cpu的使用权。

4.运行状态(running)  处于这个状态的线程占用CPU,执行程序代码。在并发运行环境中,如果计算机只有一个CPU,那么任何时刻只会有一个线程处于这个状态。只有处于就绪状态的线程才有机会转到运行状态。

5.阻塞状态(Blocked)阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才会有机会获得运行状态。

阻塞状态分为三种:

1、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

2、同步阻塞:运行的线程在获取对象同步锁时,若该同步锁被别的线程占用,则JVM会把线程放入锁池中。

3、其他阻塞:运行的线程执行Sleep()方法,或者发出I/O请求时,JVM会把线程设为阻塞状态。当Sleep()状态超时、或者I/O处理完毕时,线程重新转入就绪状态。

6.死亡状态(dead) 当线程执行完run()方法中的代码,或者遇到了未捕获的异常,就会退出run()方法,此时就进入死亡状态,该线程结束生命周期。

《2018最新 java 面试题总结(一)》

Q:死锁产生条件和应用场景

产生死锁的主要原因有三点:死锁产生的原因、必要条件和场景解析

(一)系统资源不足;

(二)进程运行推进的顺序不对;

(三)系统资源分配不当。

Q:sleep()和wait()的区别?

sleep()来自Thread类;wait()来自Object类

sleep()用于线程控制自身流程;而wait()用于线程间通信,配合notify()/notifyAll()在同步代码块或同步方法里使用

sleep()的线程不会释放对象锁;wait()会释放对象锁进入等待状态,使得其他线程能使用同步代码块或同步方法

Q: 异常处理流程,何时必须要catch:Java异常的捕获及处理

异常指程序运行过程中出现的非正常现象,例如用户输入错误、除数为零、需要处理的文件不存在、数组下标越界等。所谓异常处理,就是指程序在出现问题时依然可以正确的执行完。

异常是Java的一个重大特色,合理的使用异常处理,可以让我们程序更加的健壮。

Q: 无序数组建立二叉搜索树

二叉树遍历(前序、中序、后序、层次遍历、深度优先、广度优先)

Q: 四大引用区别和引用场景:Java中的四种引用介绍和使用场景

强引用(Strong Reference):一个对象如果具有强引用,那么垃圾回收器绝不会回收它,即使当内存不足时,VM宁愿抛出内存不足的异常,也不会去回收这些对象。

软引用 (Soft Reference): 如果一个对象只具有软引用,则内存空间足够时,垃圾回收器就不会去回收它;如果内存空间不足时,就会回收这些对象的内存。 

弱引用(Weak Reference):弱引用和软引用的区别在于,只具有弱引用的对象拥有更短暂的生命周期,在垃圾回收器线程扫描它管辖的内存区域的过程中,一旦发现对象只具有弱引用,不管当前内存空间是否足够,都会回收他的内存。

它比软引用的生命周期更短,和软引用相似,它同样可以和引用队列关联,如果被垃圾回收了,就会加入到这个关联队列中。

虚引用(Phantom Reference)几种引用都不同,虚引用并不会决定对象的生命周期,如果一个对象仅持有虚引用的话,那么它就和没有任何的引用一样,在任何时候都可能被垃圾回收器回收。 

Q:数组和链表的区别

数组:数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;

链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。

哈希表:那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。哈希表((Hash table)既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便。哈希表是由数组+链表组成的、

HashMap基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

    原文作者:唐小鹏
    原文地址: https://www.jianshu.com/p/19e6a35142e3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞