一、Java集合/泛型面试题
1、ArrayList和linkedList的区别
答: Array(数组)是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。
Array获取数据的时间复杂度是O(1),但是要删除数据却是开销很大,因为这需要重排数组中的所有数据,(因为删除数据以后,需要把后面所有的数据前移)
缺点:数组初始化必须指定初始化的长度,否则报错。
例如:
int[] a = new int[4];//推荐使用int[] 这种方式初始化
int c[] = {23,43,56,78};//长度:4,索引范围:[0,3]
List—是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式,它继承Collection。
List有两个重要的实现类:ArrayList和LinkedList。
ArrayList:可以看作是能够自动增长容量的数组。
ArrayList的toArray方法返回一个数组。
ArrayList的asList方法返回一个列表。
ArrayList底层的实现是Array,数组扩容实现。
LinkList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能,但在get与set方面弱于ArrayList。当然,这些对比都是指数据量很大或者操作很频繁。
2、 HashMap和HashTable的区别
答:
1、两者父类不同
HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。
2、对外提供的接口不同
Hashtable比HashMap多提供了elments() 和contains() 两个方法。elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。
contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。
3、对null的支持不同
Hashtable:key和value都不能为null。
HashMap:key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;可以有多个key值对应的value为null。
4、安全性不同
HashMap是线程不安全的,在多线程并发的环境下,可能会产生死锁等问题,因此需要开发人员自己处理多线程的安全问题。
Hashtable是线程安全的,它的每个方法上都有synchronized 关键字,因此可直接用于多线程中。
虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable,这样设计是合理的,因为大部分的使用场景都是单线程。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。
ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
5、初始容量大小和每次扩充容量大小不同
6、计算hash值的方法不同
3、Collection包结构,与Collections的区别
4、泛型常用特点(待补充)
答:
泛型是Java SE 1.5之后的特性, 《Java 核心技术》中对泛型的定义是:
“泛型” 意味着编写的代码可以被不同类型的对象所重用。
“泛型”,顾名思义,“泛指的类型”。我们提供了泛指的概念,但具体执行的时候却可以有具体的规则来约束,比如我们用的非常多的ArrayList就是个泛型类,ArrayList作为集合可以存放各种元素,如
Integer, String,自定义的各种类型等,但在我们使用的时候通过具体的规则来约束,如我们可以约束集合中只存放Integer类型的元素,如:
List<Integer> iniData = new ArrayList<>()
使用泛型的好处?
以集合来举例,使用泛型的好处是我们不必因为添加元素类型的不同而定义不同类型的集合。
如:整型集合类,浮点型集合类,字符串集合类。
我们可以定义一个集合来存放整型、浮点型,字符串型数据,而这并不是最重要的,因为我们只要把底层存储设置了Object即可,添加的数据全部都可向上转型为Object。
更重要的是我们可以通过规则按照自己的想法控制存储的数据类型。
5、说说List、Set、Map、三者的区别?
6、Array与ArrayList有什么不一样?
7、Map有什么特点?
8、集合类存放于Java.util包中,主要有几种接口?
答:
主要包含set(集)、 list(列表包含 Queue)和 map(映射)。
Collection: Collection 是集合 List、 Set、 Queue 的最基本的接口。
Iterator:迭代器,可以通过迭代器遍历集合中的数据
Map:是映射表的基础接口
9、什么是list接口
答:
分别是 ArrayList、 Vector 和LinkedList 。
List接口结构图
10、说说ArrayList(数组)
11、Vector(数组实现、 线程同步)
12、说说LinkList(链表)
13、什么Set集合
14、HashSet(Hash表)
答:
同) 而是按照哈希值来存的所以取数据也是按照哈希值取得。元素的哈希值是通过元素的hashcode 方法来获取的, HashSet 首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals 方法 如果 equls 结果为 true , HashSet 就视为同一个元素。如果 equals 为 false 就不是同一个元素。
哈希值相同 equals 为 false 的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。
如图 1 表示 hashCode 值不相同的情况; 图 2 表示 hashCode 值相同,但 equals 不相同的情况。
HashSet 通过 hashCode 值来确定元素在内存中的位置。 一个 hashCode 位置上可以存放多个元素。
15、什么是TreeSet(二叉树)
16、说说LinkHashSet(HashSet+LinkedHashMap)
17、HashMap(数组+链表+红黑树)
答:
HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap 最多只允许一条记录的键为 null,允许多条记录的值为 null。 HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections 的 synchronizedMap 方法使HashMap 具有线程安全的能力,或者使用 ConcurrentHashMap。 我们用下面这张图来介绍HashMap 的结构。
大方向上,HashMap里面是一个数组,然后数组中每个元素是一个单向链表。上图中,每个绿色的实体是嵌套类Entry的实例,Entry包含四个属性:key、value、hash值和用于单向链表的next。
capacity:当前数组容量,始终保持 2^n,可以扩容,扩容后数组大小为当前的2倍。
oadFactor:负载因子,默认为0.75。
threshold:扩容的阈值,等于capacity * loadFactor。
Java8对HashMap进行了一些修改, 最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。
根据Java7HashMap的介绍,我们知道,查找的时候,根据hash值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决链表的长度,为O(n)。为了降低这部分的开销,在Java8中, 当链表中的元素超过了8个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为O(logN)。
18、说说ConcurrentHashMap
19、HashTable(线程安全)
20、TreeMap(可排序)
21、LinkHashMap(记录插入顺序)
22、泛型类
答:
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
23、类型通配符?
24、类型擦除
二、Java异常面试题
1、Java中异常分为哪两种?
答:
1.编译时异常。
2.运行时异常。
2、异常的处理机制有几种?
3、如何自定义一个异常
4、try catch fifififinally,try里有return,fifinally还执行么?
5、 Excption与Error包结构
6、Thow与thorws区别
7、Error与Exception区别?
答:
1.Error和Exception都是java错误处理机制的一部分,都继承了Throwable类。
2.Exception表示的异常,异常可以通过程序来捕捉,或者优化程序来避免。
3.Error表示的是系统错误,不能通过程序来进行错误处理。
8、error和exception有什么区别
答:
error表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况
三、Java中的IO与NIO面试题
1、Java中IO流?
2、 Java IO与NIO的区别
3、常用io类有那些
答:
File FileInputSteam,FileOutputStream
BufferInputStream,BufferedOutputSream PrintWrite FileReader,FileWriter
BufferReader,BufferedWriter ObjectInputStream,ObjectOutputSream
4、字节流与字符流的区别
5、阻塞IO模型
6、非阻塞IO模型
答:
当用户线程发起一个read操作后,并不需要等待,而是马上就得到了一个结果。 如果结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。所以事实上,在非阻塞IO模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞IO不会交出CPU,而会一直占用CPU。
典型的非阻塞IO模型一般如下:
while(true){
data = socket.read();
if(data!= error){
//处理数据 break; }
}
但是对于非阻塞IO就有一个非常严重的问题, 在while循环中需要不断地去询问内核数据是否就绪,这样会导致CPU占用率非常高,因此一般情况下很少使用while循环这种方式来读取数据。
7、多路复用IO模型
8、信号驱动IO模型
9、异步IO模型
10、JAVA NIO
11、NIO的缓冲区
12、NIO的非阻塞
13、Channel
14、Buffffer
答:
Buffer,故名思意, 缓冲区,实际上是一个容器,是一个连续数组。 Channel提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由Buffer。
上面的图描述了从一个客户端向服务端发送数据,然后服务端接收数据的过程。客户端发送数据时,必须先将数据存入Buffer 中,然后将Buffer中的内容写入通道。服务端这边接收数据必须通过Channel将数据读入到Buffer中,然后再从Buffer中取出数据来处理。
在NIO中, Buffer是一个顶层父类,它是一个抽象类,常用的Buffer的子类有:ByteBuffer、 IntBuffer、 CharBuffer、 LongBuffer、DoubleBuffer、 FloatBuffer、ShortBuffer。
15、Selector
答:
Selector类是NIO的核心类, Selector能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个事件进行相应的响应处理。这样一来,只是用一个单线程就可以管理多个通道,也就是管理多个连接。这样使得只有在连接真正有读写事件发生时,才会调用函数来进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程,并且避免了多线程之间的上下文切换导致的开销。
四、Java反射面试题
1、除了使用new创建对象之外,还可以用什么方法创建对象?
2、Java反射创建对象效率高还是通过new创建对象的效率高?
3、java反射的作用
4、哪里会用到反射机制?
答:
jdbc就是典型的反射
Class.forName('com.mysql.jdbc.Driver.class');//加载MySQL的驱动类
这就是反射。如hibernate,struts等框架使用反射实现的。
5、反射的实现方式:
6、实现Java反射的类:
7、反射机制的优缺点:
8、Java反射API
9、反射使用步骤(获取Class对象、调用对象方法)
10、获取Class对象有几种方法
11、利用反射动态创建对象实例
答:
Class对象的 newInstance()
使用Class对象的 newInstance()方法来创建该Class对象对应类的实例,但是这种方法要求该Class对象对应的类有默认的空构造器。
调用 Constructor 对象的 newInstance()
先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()
方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例。
//获取 Person 类的 Class 对象
Class clazz=Class.forName("reflection.Person");
//使用.newInstane 方法创建对象
Person p=(Person) clazz.newInstance();
//获取构造方法并创建对象
Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class); //创建对象并设置属性13/04/2018
Person p1=(Person) c.newInstance("李四","男",20)
五、Java序列化面试题
1、什么是java序列化,如何实现java序列化?
2、保存(持久化)对象及其状态到内存或者磁盘
3、序列化对象以字节数组保持-静态成员不保存
答:
使用 Java 对象序列化, 在保存对象时,会把其状态保存为一组字节,在未来, 再将这些字节组装成对象。必须注意地是, 对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
4、序列化用户远程对象传输
5、Serializable 实现序列化
6、writeObject和readObject自定义序列化策略
7、序列化ID
答:
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化ID是否一致(就是 privatestatic final long serialVersionUID
8、序列化并不保存静态变量
9、Transient关键字阻止该变量被序列化到文件中
10、序列化(深clone一中实现)
答:
在 Java 语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
六、Java注解面试题
1、种标准元注解是哪四种?
答:
元注解的作用是负责注解其他注解。 Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。
@Target 修饰的对象范围
@Target说明了Annotation所修饰的对象范围: Annotation可被用于packages、types(类、接口、枚举、Annotation 类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch 参数)。在 Annotation 类型的声明中使用了target可更加明晰其修饰的目标。
@Retention 定义 被保留的时间长短
Retention 定义了该 Annotation 被保留的时间长短:表示需要在什么级别保存注解信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效),取值(RetentionPoicy)由:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在 class 文件中有效(即 class 保留)
RUNTIME:在运行时有效(即运行时保留)
@Documented 描述-javadoc
@ Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
@Inherited阐述了某个被标注的类型是被继承的
@Inherited元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation 将被用于该class的子类。
2、注解是什么?
答:
Annotation(注解)是Java提供的一种对元程序中元素关联信息和元数据(metadata)的途径和方法。 Annatation(注解)是一个接口,程序可以通过反射来获取指定程序中元素的Annotation对象,然后通过该Annotation对象来获取注解中的元数据信息。