面试题整理
该文章转自csdn,手打一遍加深记忆(狗头)
1. JDK和JRE的区别
JDK:Java Development Kit的简称,java开发工具包,提供了java的开发环境和运行环境
JRE:Java Runtime Environment的简称,Java运行环境,为java的运行提供了所需环境
2. ==和equals的区别
对于基本类型和引用类型==的效果是不一样的,如下所示
- 基本类型:比较的是值是否相同;
- 引用类型:比较的是引用(地址)是否相同;
String x="string";
String y="string";
String z= new String("string");
x==y;//true
x==z;//false
x.equals(y);//true
x.equals(z);//true
这里的x和y直接使用"string",这里是直接在常量池里创建了字符串,并给与两者一起引用,所以==是true,而new String()方法重写开辟了内存空间,所以为false。
而equals()方法本质上是==,但如String、Integer重写了equals方法,把它变成了值的比较。而如果我们自己创建的类并没有重写equals方法,其默认比较的依然是引用。
3.两个对象的hashCode()相同,则equals()也一定为true,对吗?
不对,如
String str1="通话";
String str2="重地";
两者hashCode是相等的,但实际上equals并不相同, 原因是hashCode相等仅仅表示两者键值对的哈希值相等,但并不一定表示键值对相等,但反之,equals为true,hashCode就一定相等。
4.final在java中的用处
- final修饰的类叫最终类,该类不能被继承
- final修饰的方法不能被重写
- final修饰的变量叫常量,必须实现初始化,初始化之后值就不能被修改了,与之区分的是被static修饰的变量叫静态变量。
5.java中的Math.round(-1.5)等于多少
等于-1,该方法为“四舍五入”方法,但实际使用取整是向右取整的,因此为-1。
6.String属于基础的数据类型吗?
不属于,Java的基础数据类型有 byte、boolean、char、short、int、float、long、double
7.Java中的操作字符串有哪些类,它们之间的区别?
操作字符串的类有:String、StringBuffer、StringBuilder。 String和StringBuffer、StringBuilder最大的区别在于,StringBuffer是线程安全的,而StringBuilder是非线程安全的,但StringBuilder的性能却高于StringBuffer,所以在单线程环境下推荐使用StringBuilder,多线程环境下使用StringBuffer。
8.String str="i"和String str=new String("i")一样吗?
不一样,两者内存分配方式不同,使用="i"方式,java虚拟机会将其分配到常量池,如果常量池内存在,则指向常量池内的string,而new String则会被分配到堆内存中。
9.如何将字符串反转
使用StringBuilder或者StringBuffer的reverse()方法。
10.String类的常用方法有?
- indexOF():返回指定字符的索引。
- charAt():返回指定索引处的字符。
- replace():字符串替换。
- trim():去除字符串两端空白
- split():分割字符串,返回一个分割后的字符串数组。
- getBytes():返回字符串的byte类型数组。
- length():返回字符串长度。
- toLowerCase():字符串转换为小写字母。
- toUpperCase():字符串转换为大写字母。
- substring():截取字符串。
- equals():字符串比较。
11.抽象类必须要有抽象方法吗?
不需要,抽象类不一定要有抽象方法。
12.普通类和抽象类有哪些区别?
- 普通类不能包含抽象方法,抽象类可以。
- 抽象类不能直接实例化,普通类可以。
13.抽象类能使用final修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为final该类就不能被继承,这样就产生矛盾了。
14.接口和抽象类有什么区别?
- 实现:抽象类的子类使用extends来继承;接口必须使用implments来实现接口。
- 构造函数:抽象类可以有构造函数,接口不能。
- 实现数量:类可以有多个接口,但只能继承一个抽象类。
- 访问修饰符:接口中的方法默认使用public修饰,抽象类中的方法可以是任意访问修饰符。
15.Java中的IO流分为几种?
按功能来分:输入流(input)、输出流(output)
按类型来分:字节流和字符流
字节流和字符流的区别是:字节流按8位传输以字节为单位输入输出数据,字符流按16位传输以字符位单位输入输出数据。
16.BIO、NIO、AIO有什么区别
- BIO:Block IO同步阻塞式IO,就是我们平常使用的传统IO,它的特点是模式简单使用方便,并发处理能力低。
- NIO:Non IO同步非阻塞IO,是传统IO的升级,客户端和服务器端通过CHannel(通道)通讯,实现了多路复用。
- AIO:Asynchronous IO 是NIO的升级,也叫NIO2,实现了异步非堵塞IO,异步IO的操作基于事件和回调机制。
17.Files的常用方法都有哪些?
- Files.exists():检测文件路径是否存在。
- Files.createFile():创建文件。
- Files.createDirectory():创建文件夹。
- Files.delete():删除一个文件或目录。
- Files.copy():复制文件。
- Files.move():移动文件。
- Files.size():查看文件个数。
- Files.read():读取文件。
- Files.write():写入文件。
18.java容器有哪些?
Java容器分为Collection和Map两大类,其下有许多子类
- Collection
- List
- ArrayList
- LinkedList
- Vector
- Stack
- Set
- HashSet
- LinkedHashSet
- TreeSet
- List
- Map
- HashMap
- LinkedHashMap
- TreeMap
- ConcurrentHashMap
- Hashtable
- HashMap
19.Collection和Collections有什么区别?
- Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如List、Set等。
- Collections是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类。
20.List、Set、Map之间的区别是什么?
List、Set、Map的主要区别为两个方面:元素是否有序、是否允许元素重复。区别如下:
子类 | 元素有序 | 允许元素重复 | |
---|---|---|---|
List | 是 | 是 | |
Set | AbstractSet | 否 | 否 |
Set | HashSet | 否 | 否 |
Set | TreeSet | 是(二叉树排序) | 否 |
Map | AbstractMap | 否 | Key值必须唯一,value可重复 |
Map | HashMap | 否 | Key值必须唯一,value可重复 |
Map | TreeMap | 是(二叉树排序) | Key值必须唯一,value可重复 |
21.HashMap和Hashtable有什么区别?
- 存储:HashMap允许key和value为null,而Hashtable不允许。
- 线程安全:Hashtable是线程安全的,而HashMap是不安全的。
- 推荐使用:在Hashtable的类注释可以看到,Hashtable是保留类不建议使用,推荐在单线程环境下使用HashMap代替,如果需要多线程使用则用ConcurrentHashMap代替。
22.如何决定使用HashMap还是TreeMap?
对于在Map中插入、删除、定位一个元素这类操作,HashMap是最好的选择,因为相对而言HashMap的插入会更快,但如果你要对一个key集合进行有序的遍历,那TreeMap是更好的选择。
23.说一下HashMap的实现原理?
HashMap是给予Hash算法实现的,它通过put(key,value)方法存储,get(key)方法获取,当传入值时,HashMap会根据key的HashCode()的哈希值再次计算hash值(相当于两次hash计算),根据哈希值将value保存在bucket里。当计算出的哈希相同时(哈希冲突),HashMap会使用链表和红黑树来存储相同hash值的value。
当map的数组长度大于等于64,链表长度大于等于8,再次向该链表put时,会进行树化。
数组长度小于64,链表长度小于6时会反树化。
24.说一下HashSet的实现原理?
HashSet是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet的实现比较简单,其相关操作基本都是直接调用HashMap底层的相关方法实现的,HashSet不允许重复的值。
25.ArrayList和LinkedList的区别是什么?
- 数据结构实现:ArrayList是动态数组的数据结构实现,而LinkedList是双向链表实现。
- 随机访问效率:在随机访问下,ArrayList效率更高,因为LinkedList是线性的数据存储,需要移动指针从前往后依次查找。
- 增加和删除效率:在非首尾的增删中,LinkedList效率更高,因为ArrayList在增删操作时会影响数组内其他数据的下标。
26.如何实现数组和List之间的转换?
- 数组转List:使用Arrays.asList(array)进行转换
- List转数组:使用List自带的toArray()方法转换。
27.ArrayList和Vector的区别是什么?
- 线程安全:Vector使用了Synchronized方法来实现线程同步,是线程安全的,而ArrayList是非线程安全的。
- 性能:ArrayList在性能方面要优于Vector。
- 扩容:ArrayList和Vector都会根据实际的需要动态的调整容量,只不过Vector扩容每次增加1倍,而ArrayList只增加一半。
28.Array和ArrayList有什么区别?
- Array可以存储基本数据类型和对象,ArrayList只能存储对象
- Array是指定固定大小的,而ArrayList大小是自动拓展的。
- Array内置方法没有ArrayList多,比如addAll、removeAll、iteration等。
29.在Queue中poll()和remove()有什么区别?
- 相同点:都是返回第一个元素,并在队列中删除返回的对象。
- 不同点:如果没有元素poll()会返回null,而remove()会直接抛出NoSuchElementException异常。
30.哪些集合类是线程安全的?
Vector、Hashtable、Stack都是线程安全的,而像HashMap则是非线程安全的,不过在JDK1.5之后随着Java.util.concurrent并发包的出现,它们也有了自己对应的线程安全类,比如HashMap对应的线程安全类就是ConcurrentHashMap。
31.迭代器Iterator的什么?
Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration,迭代器允许调用者在迭代过程中移除元素。
32.Iterator怎么使用?有什么特点?
Iterator使用如下:
List<String> list =new ArrayList<>();
Iterator<String> it=list.iterator();
while(it.hasNext()){
String obj=it.next();
System.out.println(obj);
}
Iterator的特点是更安全,因为它可以确保,在当前遍历的集合元素被更改时,会抛出ConcurrentModificationException异常。
33.Iterator和ListIterator有什么区别?
- Iterator可以遍历Set和List集合,而ListIterator只能遍历List。
- Iterator只能单向遍历,而ListIterator可以双向遍历。
- ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换元素、获取前后元素的索引位置。
34.怎么确保一个集合不能被修改?
可以使用Collections.unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出Java.lang.UnsupportedOperationException异常。如:
List<String> list=new ArrayList<>();
list.add("x");
Collection<String> clist=Collections.unmodifiableCollection(list);
clist.add("y");//报错
35.并行和并发有什么区别?
- 并行:多个处理器或多核处理器同时处理多个任务。
- 并发:多个任务在同一个CPU核上,按细分的时间片轮流执行,从逻辑上来看那些任务是同时执行。
36.线程和进程的区别?
一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。 进程是资源分配的最小单位,线程是Cpu调度的最小单位
37.守护线程是什么?
守护进程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某种发生的事件。
38.创建线程的几种方法
- 继承Thread重写run方法 2.实现Runnable接口 3.实现Callable接口
39.说一下runnable和callable有什么区别?
runnable没有返回值,callable可以拿到返回值,callable可以看做是runnable的补充。
40.线程有哪些状态?
线程的状态:
- NEW 尚未启动
- RUNNABLE 正在执行中
- BLOCKED 阻塞的(被同步锁或者IO锁阻塞)
- WAITING 永久等待状态
- TIMED_WAITING 等待指定的时间重写被唤醒的状态
- TERMINATED 执行完成
41.sleep()和wait()方法的区别
- 类的不同:sleep()来自Thread类,wait()来自Object
- 释放锁:sleep()不释放锁,wait()释放锁
- 用法不同:sleep()时间到自动唤醒,wait()只能用notify()/notifyAll()来唤醒
42.notify()和notifyAll()有什么区别?
notifyAll()会唤醒所有线程,让所有线程去争抢锁,notify()之后会随机唤醒一个线程,让它自己去争抢锁。 所有本质在应用上,两者的使用是一样的,但由于使用notify()是随机唤醒一个线程,存在某一线程始终不被唤醒的情况,因此一半使用notifyAll()来让线程自己争夺。
43.线程的run()和start()有什么区别?
start()方法用于启动线程,run()方法用于执行线程的运行时代码。run()可以重复调用,而start()只能调用一次。
44.创建线程池有哪几种方式?
- newSingleThreadExecutor():特点是工作线程数目被限制为1,操作一个无界的工作队列,所以它保证了所有任务都是被顺序执行,最多会有一个任务处于活动状态,并且不允许是一种改动线程池实力,因此可以避免其改变线程数目;
- newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的线程;如果线程闲置时间超过60秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作队列。
- newFixedThreadPool():重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThread个工作线程是活动的。这意味着,如果任务数量超过了活动队列的数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足nThreads。
- newSingleThreadScheduledExecutor():创建单线程池,返回ScheduledExecutorService,可以进行定时或周期性的工作调度。
- newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()类似,创建的是一个ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程。
- newWorkStealingPool(int parallelism):java 8 加入的创建方法,内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序。 ThreadPoolExecutor():是最原始的线程池创建。
45.线程池都有哪些状态?
- RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
- SHUTDOWN:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
- STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
- TIDYING:所有的任务都销毁了,workCount为0,线程池的状态转换为TIDYING状态时,会执行钩子方法terminated()
- TERMINATED:terminated()方法结束后,线程池状态会变为此状态。
46.线程池中submit()和execute()方法有什么区别?
- execute():只能执行Runnable类型的任务
- submit():可以执行Runnable和Callable类型的任务。
47.在Java程序中怎么保证多线程的运行安全?
- 使用安全类,比如java.util.concurrent下的类
- 使用自动锁synchronized。
- 使用手动锁Lock。
48.什么是死锁
当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个锁由于互相持有对方需要的锁,而发生阻塞的现象,我们称之死锁。
49.死锁的条件
- 互斥原则:同一资源同时只能由一个线程读取
- 不可抢占:不可以强行剥夺线程抢占的资源
- 请求和保持:线程在请求其他资源时,对持有资源保持不放
- 循环等待条件:在互相等待资源中,形成闭环
50.怎么防止死锁
- 尽量使用使用tryLock的方法,设置超时时间,超时可以退出防止死锁。
- 尽量使用Java.util.concurrent类来代替自己的手写锁
- 尽量降低锁的使用粒度,尽量不要几个功能用同一把锁
- 尽量减少同步的代码块
51.ThreadLocal是什么?有哪些使用场景?
ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。 ThreadLocal的经典使用场景是数据库连接和session管理等。
52.说一下synchronized底层实现原理?
synchronized是由一对monitorenter/monitorexit指令实现的,monitor对象是同步的基本实现单位,在java6之前,monitor的实现完全依靠操作系统内部的互斥锁,因为需要进行用户态到内核态的切换,所以同步操作是一个无差别的重量级操作,性能也很低。但在Java6的时候,虚拟机对此进行了改进,提供了三种不同的monitor实现,也就是常说的三种不同的锁:偏向锁、轻量级锁、重量级锁,大大改进了其性能。
53.synchronized和volatile的区别是什么?
- volatile是变量修饰符,synchronized是修饰类、方法、代码段。
- volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
- volition不会造成线程的阻塞,synchronized可能会造成线程的阻塞。
54.synchronized和Lock有什么区别?
- synchronized可以给类、方法、代码块加锁;而lock只能给代码块加锁。
- synchronized不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而lock需要自己加锁和释放锁,如果使用不当没有释放,会造成死锁。
- 提供Lock可以知道有没有成功获取到锁,而synchronized无法办到。
55.synchronized和ReentrantLock区别是什么?
synchronized早期的实现比较低效,对比ReentrantLock,大多数场景性能都相差较大,但是在Java6中对synchronized进行了非常多的改进。 主要区别如下:
- ReentrantLock 使用起来比较灵活,但必须有释放锁的配合动作。
- ReentrantLock必须手动获取与释放锁,而synchronized不需要手动释放和开启锁。
- ReentrantLock 只适合于代码块锁,而synchronized可用于装饰方法、代码块等。
56.说一下atomic的原理?
atomic主要利用CAS和volatile和native方法来保证原子操作,从而避免synchronized的高开销,执行效率大为提升。
反射
57.什么是反射
反射是在运行中的的状态,对于任意类,都能够知道这个类的所有属性和方法;对于任意对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称之为反射机制。
58.什么是Java序列化,什么情况下需要序列化?
java序列化是为了保存对象在内存中的状态,并且能够把这个状态再读出来。 需要序列化的场景
- 想把内存中对象的状态保存至文件或数据库中。
- 想通过套接字在网络上传递对象。
- 箱通过RMI传输对象
59.动态代理是什么?有哪些应用?
动态代理是运行时动态生成代理类 动态代理的应用有spring aop,测试框架的后端mock、rpc、Java注解对象获取等。
60.怎么实现动态代理
JDK原生动态代理和cglib动态代理。JDK原生动态代理是基于接口实现的,而cglib是基于继承当前类的子类实现的。
61.为什么要使用克隆
克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就需要克隆了。
62.如何实现对象克隆?
- 实现Cloneable接口并重写Object类的clone()方法。
- 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
63.深拷贝和浅拷贝区别是什么?
- 浅拷贝:当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
- 深拷贝:除了复制对象本身外,对象所包含的所有成员变量也将复制。
Java Web
64.JSP和servlet有什么区别?
JSP是servlet技术的拓展,本质上是servlet的简易方式。
65.session和cookie在区别
- 存储位置不同:session存储在服务器端,cookie存储在浏览器
- 安全性不同:cookie安全性一般,可以被篡改和伪造
- 容量和个数限制:cookie存在容量限制,同一站点下的cookie也有个数限制
- 存储多样性:cookie只能存储在浏览器,session可以存储在Redis,数据库等
66.session的工作原理
session工作原理是客户端登录完成后,服务器会创建对应的session,创建之后会将session的id发送给客户端,客户端再存储到浏览器。这样每次向服务器请求时都会带着sessionid,服务器拿到sessionid之后在内存找到与之对应的session即可。
67.如何避免SQL注入
- 使用预处理PreparedStatement。
- 使用正则表达式过滤掉字符中的特殊字符。
异常
74.throw和throws的区别?
- throw:是真实抛出一个异常
- throws:声明可能会抛出的异常
75.final、finally、finalize有什么区别?
- final:是修饰符,如果修饰类,此类不能被继承;如果修饰方法和变量,表示此方法和变量不能被修改,只能使用。
- finally:是try{}catch{}finally{}的最后一步,无论发生什么情况,都会执行。
- finalize:是object类的方法,在垃圾收集器执行的时候被回收对象的此方法会被调用。
76.try-catch-finally哪个部分可以省略?
catch和finally都可以省略,但最多省略其中一个。
77.try-catch-finally。如果catch中return了,finally还会执行吗?
finally一定会执行,如果return了,return会在finally执行之后执行。
78.常见的异常有哪些?
- NullPointerException 空指针异常
- ClassNotFoundException 指定类不存在异常
- NumberFormatException 字符串转换为数字类异常
- IndexOutOfBoundsException 数组下标越界异常
- ClassCastException 数据类型转换异常
- FileNotFoundException 文件未找到异常
- NoSuchMethodException 方法不存在异常
- IOException IO异常
- SocketException Socket异常