同事面试了半个月总结出的面试题以及答案,希望能帮助到正在面试的伙伴。
1.“”和equals方法有什么区别?
对于基本数据类型变量利用来判断他们存储的值是否相同;对于引用类型变量,比较的是他的地址。而且涉及到基本数据类型包装类(,equals)包装类又涉及是否自动拆箱,integer a=128;integer b=128;a==b?
一般我们会重写equals方法。
2.“&”和“&&”的区别?
&和&&都是逻辑与的运算符,表示逻辑(and),当运算符两边都为true时,整个运算符结果为true,负责只要一方为false,结果都是false;
而&&和&的区别是,&&可以提升程序运行的效率,具有短路的功能。而&是可以做位运算符,如果两边的表达式都不是boolean,那么&按位与操作。
3.匿名内部类是否可以继承其他类,是否可以实现继承其他类,是否可以实现接口?
匿名内部类不可以继承其他类,但是匿名内部类可以实现外部接口。
4.HashMap的实现原理
HashMap是数组+链表实现的,既然用到Hash散列,那么肯定不可避免地会出现冲突问题,HashMap解决冲突的方法是拉链法,因为这里有用到数组,那么当容量不够的时候就需要进行扩容,在HashMap中有个术语冲突,当冲突比例越来越高的呢?就当我们的·素数个数超过了数组原先大小的装填因子,默认情况下的装填因子是0.75,扩容的有一个坏处就是每一次扩容之后都必须计算原先数组中的元素在新数组中的存储位置,这样比较消耗性能,所以一般近况下如果你已经能够确定要多大散列范围的数组的话,建议还是能够指定大小来扩容。接下来就是HashMap的put和set原理了。
put 操作和set 操作,操作的主要对象是Key,如果你查到的源码的话,会发现value只是跟着Key的步伐在走而已,并没有实际进行操作,对于put ,首先会计算出来的hash值在数组的下标位置,查看该位置是不是对应链表为空,为空的话,直接将当前的键值对插入到该链表首位,不会执行当前的对象的equais方法,如果不为空的话,会通过for循环来通过key的equals方法来查看链表中有没有与当前键值相等的键值对Entry存在。
5.谈谈final, finally, finalize的区别。
final?修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能被继承声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载 。
finally?在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
finalize?方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
6.HashMap和Hashtable的区别。
都属于Map接口的类,实现了将位一键映射到特定的值上。
HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。
Hashtable 类似于 HashMap,但是不允许 null 键和 null 值。它也比 HashMap 慢,因为它是同步的。
7.String s = new String(“xyz”);创建了几个String Object?
两个对象,一个是“xyx”,一个是指向“xyx”的引用对象s。
8.sleep() 和 wait() 有什么区别?
sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非以下情况:
(a)“醒来”的线程具有更高的优先级 。
(b)正在运行的线程因为其它原因而阻塞。
wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。
9.short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
short s1 = 1; s1 = s1 + 1;有错,s1是short型,s1+1是int型,不能显式转化为short型。可修改为s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正确。
10.Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
11.Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。
equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。
12.error和exception有什么区别?
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
13.给我一个你最常见到的runtime exception。(我就不细说了,常见的我都整理出来了)
ArithmeticException, ArrayStoreException,
BufferOverflowException, BufferUnderflowException,
CannotRedoException, CannotUndoException,
ClassCastException, CMMException,
ConcurrentModificationException, DOMException,
EmptyStackException, IllegalArgumentException,
IllegalMonitorStateException, IllegalPathStateException,
IllegalStateException, ImagingOpException,
IndexOutOfBoundsException, MissingResourceException,
NegativeArraySizeException, NoSuchElementException,
NullPointerException, ProfileDataException,
ProviderException, RasterFormatException, SecurityException,
SystemException, UndeclaredThrowableException,
UnmodifiableSetException, UnsupportedOperationException
14.abstract class和interface有什么区别?
声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法
接口(interface)是抽象类的变体*。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final 成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口
15.ArrayList与LinkedList的区别
1、ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 (LinkedList是双向链表,有next也有previous)
2、对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3、对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
16.ArrayList遍历时正确删除元素
删除元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。
17. Arrays.sort 实现原理和 Collection 实现原理
在jdk7以前的版本中sort()的实现原理是:基本类型使用优化后的快速排序,其他类型使用优化后的归并排序,jdk7以后如果jdk7以后修改了排序策略:如果JVM启动参数配置了-Djava.util.Arrays.useLegacyMergeSort%3Dtrue+那么就会执行上面所说的排序策略(优化的归并排序),否则将会执行TimSort排序。&oq=在jdk7以前的版本中sort()的实现原理是:基本类型使用优化后的快速排序,其他类型使用优化后的归并排序,jdk7以后如果jdk7以后修改了排序策略:如果JVM启动参数配置了-Djava.util.Arrays.useLegacyMergeSort%3Dtrue++那么就会执行上面所说的排序策略(优化的归并排序),否则将会执行TimSort排序。
事实上Collections.sort方法底层就是调用的array.sort方法
18.BeanFactory 和 ApplicationContext
BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:
? MessageSource, 提供国际化的消息访问
? 资源访问,如URL和文件
? 事件传播
? 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
19.break和continue的作用
break: 结束当前循环并退出当前循环体。
break还可以退出switch语句
continue: 循环体中后续的语句不执行,但是循环没有结束,继续进行循环条件的判断(for循环还会i++)。continue只是结束本次循环
20.char型变量中能不能存贮一个中文汉字?为什么?
char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。
21.Class类的作用?生成Class对象的方法有哪些?
Class类是Java 反射机制的起源和入口,用于获取与类相关的各种信息,提供了获取类信息的相关方法。Class类继承自Object类
Class类是所有类的共同的图纸。每个类有自己的对象,好比图纸和实物的关系;每个类也可看做是一个对象,有共同的图纸Class,存放类的 结构信息,能够通过相应方法取出相应信息:类的名字、属性、方法、构造方法、父类和接口
方 法
示 例
对象名
.getClass()
String str=“bdqn”;
Class clazz = str.getClass();
对象名
.getSuperClass()
Student stu = new Student();
Class c1 = stu.getClass();
Class c2 = stu.getSuperClass();
Class.forName()
Class clazz = Class.forName(“java.lang.Object”);
Class.forName(“oracle.jdbc.driver.OracleDriver”);
类名.class
类名.class
Class c2 = Student.class;
Class c2 = int.class
包装类.TYPE
包装类.TYPE
Class c2 = Boolean.TYPE;
23.Collection和Collections的区别?
Collection是一个接口,它是Set、List等容器的父接口;Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。
24.Comparable和Comparator接口是干什么的?列出它们的区别
Java提供了只包含一个compareTo()方法的Comparable接口。这个方法可以个给两个对象排序。具体来说,它返回负数,0,正数来表明输入对象小于,等于,大于已经存在的对象。
ava提供了包含compare()和equals()两个方法的Comparator接口。compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。equals()方法需要一个对象作为参数,它用来决定输入参数是否和Comparator相等。只有当输入参数也是一个Comparator并且输入参数和当前Comparator的排序结果是相同的时候,这个方法才返回true。
25.ConcurrenHashMap介绍1.8 中为什么要用红黑树?
java8不是用红黑树来管理hashmap,而是在hash值相同的情况下(且重复数量大于8),用红黑树来管理数据。 红黑树相当于排序数据。可以自动的使用二分法进行定位。性能较高。
在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中:
ConcurrentHashMap中默认是把segments初始化为长度为16的数组。
根据ConcurrentHashMap.segmentFor的算法,3、4对应的Segment都是segments[1],7对应的Segment是segments[12]。
(1)Thread1和Thread2先后进入Segment.put方法时,Thread1会首先获取到锁,可以进入,而Thread2则会阻塞在锁上:
(2)切换到Thread3,也走到Segment.put方法,因为7所存储的Segment和3、4不同,因此,不会阻塞在lock():
既然不能全锁(HashTable)又不能不锁(HashMap),所以就搞个部分锁,只锁部分,用到哪部分就锁哪部分。一个大仓库,里面有若干个隔间,每个隔间都有锁,同时只允许一个人进隔间存取东西。但是,在存取东西之前,需要有一个全局索引,告诉你要操作的资源在哪个隔间里,然后当你看到隔间空闲时,就可以进去存取,如果隔间正在占用,那你就得等着。
26.hashCode()和equals()方法的重要性体现在什么地方
通过hashCode和equals方法保证元素的唯一性,当重写equals方法时,必须重写hashCode方法,因为如果不重写这两个方法,就会默认使用Object的方法,一般是不相同的,所以就会导致存储了重复值,与hashset、hashmap等性质冲突。
27.hashCode方法的作用?
hashcode这个方法是用来鉴定2个对象是否相等的。与equals方法的区别:
①一般来讲,equals这个方法是给用户调用的,如果你想判断2个对象是否相等,你可以重写equals方法,然后在代码中调用,就可以判断他们是否相等了。简单来讲,equals方法主要是用来判断从表面上看或者从内容上看,2个对象是不是相等。举个例子,有个学生类,属性只有姓名和性别,那么我们可以认为只要姓名和性别相等,那么就说这2个对象是相等的。
②hashcode方法一般用户不会去调用,比如在hashmap中,由于key是不可以重复的,他在判断key是不是重复的时候就判断了hashcode这个方法,而且也用到了equals方法。这里不可以重复是说equals和hashcode只要有一个不等就可以了!所以简单来讲,hashcode相当于是一个对象的编码,就好像文件中的md5,他和equals不同就在于他返回的是int型的,比较起来不直观。我们一般在覆盖equals的同时也要覆盖hashcode,让他们的逻辑一致。举个例子,还是刚刚的例子,如果姓名和性别相等就算2个对象相等的话,那么hashcode的方法也要返回姓名的hashcode值加上性别的hashcode值,这样从逻辑上,他们就一致了。
③要从物理上判断2个对象是否相等,用==就可以了。
28.HashMap实现原理
HashMap是数组+链表实现的,既然用到hash散列,那么肯定不可避免地会出现冲突问题,HashMap解决冲突的方法是拉链法,因为这里有用到数组,那么当容量不足的时候就需要进行扩容操作了,在HashMap中有个术语叫冲突,当冲突几率越来越高的时候就需要进行扩容操作了,那什么情况就叫冲突几率高呢?就是当我们的数组元素个数超过了数组原先大小*装填因子,默认情况下的装填因子是0.75,扩容有个坏处就是每次扩容之后都必须重新计算原先数组中的元素在新数组中的存储位置,这点比较消耗性能,所以一般情况下如果你已经能够确定最大需要多大散列范围的数组的话,建议还是能够指定大小;
接下来就是HashMap的put和set原理了:
put操作和set操作进行操作的对象是主要是key,如果你查看源码的话会发现value只是跟着key的步伐在走而已,并没有实质性的进行操作,对于put操作,首先会计算出当前key对应的hash值,接着找到计算出来的hash值在数组中的下标位置,查看该下标位置处对应的链表是否为null,为空的话直接将当前键值对插入到该链表首位,不会执行当前key对象的equals方法;如果下标位置处对应的链表不为null的话,会通过for循环来通过key的equals方法来查看这个链表中有没有与当前键值相等的键值对Entry存在,有的话,会用当前值替换原先这个键值对的value值,遍历结束如果不存在的话,会将当前键值对插入到链表的头部,这个就是put过程了;
get操作过程思想可以借助于put过程,首先会计算出当前key值的hash值,接着找到此hash值在数组中的位置,找到这个位置对应的链表,接着通过for循环遍历这个链表,遍历过程中调用equals方法查看有没有等于当前key的键值对存在,有的话直接返回这个键值对对应的value值即可;
HashMap注意点:
HashMap是非线程安全的,也就是说你在使用迭代器的过程中有其他线程修改了map的话,你的程序可能会抛出ConcurrentModificationException异常,这就是我们常见的fail-fast机制了,原因在于我们在调用HashMap的迭代器里面的每个方法的时候,都会通过判断原先map被修改次数和当前被修改次数是否相等,不等的话直接就抛出了ConcurrentModificationException异常了,这点在ArrayList里面使用迭代器也会出现,具体解决方法就是使用ConcurrentHashMap代替HashMap了;
HashMap是允许你的键或者值为null的;
HashMap是不能保证随着时间的推移,你里面元素之间的顺序不变,原因就在于map中存放hash值的数组在扩容的时候会重新计算原先元素在新数组中位置的;
29.HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的
DK1.7用的链表散列结构,JDK1.8用的红黑树
在扩充HashMap的时候,JDK1.7的重新计算hash,
JDK1.7只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap;
DK1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,但是从上图可以看出,JDK1.8不会倒置
30.HashMap 是线程安全的吗,为什么不是线程安全的
不是线程安全的。
不安全的原因. resize死循环
总结:看完这些面试题,有何感触,是不是都可以回答上来呢,希望这些面试题能帮助到你,如果对你有帮助,不妨点赞关注支持一下吧。
本文暂时没有评论,来添加一个吧(●'◡'●)