最近辞职准备面试,顺便整理一下面试题分享给大家,如有错误欢迎指出
01. 你对面向对象思想的理解?
面向对象编程简称OOP,是开发程序的一种方法、思想。
面向过程编程中常常会导致所有的代码都在一起,难以阅读和维护,牵一动百。而OOP,使用许多代码模块,每个模块都只提供特定的功能,彼此独立,可以增加代码重用几率,更加有利于软件的开发、维护和升级。
另外OOP的三大核心特性:继承、封装、多态 的特性,使得程序员能够设计出高内聚、低耦合的系统结构,使得系统更灵活、易扩展,成本较低
02. 很多程序员都知道多态,但大都知其然不知其所以然,说说你对多态的理解
一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,在编程时并不确定,而是在程序运行期间才确定。
因为在程序运行时才确定具体的类,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性
多态的优点:解耦、灵活、可扩展性强
多态存在的三个必要条件:继承、重写、父类引用指向子类对象
03. Collection集合有什么子类
List
1.可以允许重复的对象。
2.可以插入多个null元素。
3.有序,保持元素的插入顺序
4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。
Set
1.不允许重复对象
2.无序
3.只允许一个 null 元素
4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口。
Map
1.Map不是collection的子接口或者实现类。Map是一个接口。
2.Map 可能会持有相同的值对象但键对象必须是唯一的。
3.TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
4.Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)
04. list,set,map的使用场景
1.如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。
2.如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。
3.如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。
4.如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。
05. ArrayList和HashMap的比较
使用场景:如果需要快速随机访问元素,应该使用ArrayList。需要键值对形式的数据时,应该使用HashMap
相同点:
1)都是线程不安全,不同步
2)都可以储存null值
3)获取元素个数方法一样,都用size()方法获取
区别:
1)实现的接口
ArrayList实现了List接口(Collection(接口)->List(接口)->ArrayList(类)),底层使用的是数组;而HashMap现了Map接口(Map(接口)->HashMap(类)),底层使用的是Hash算法存储数据。
2)存储元素
ArrayList以数组的方式存储数据,里面的元素是有顺序,可以重复的;而HashMap将数据以键值对的方式存储,键的哈希码(hashCode)不可以相同,相同后面的值会将前面的值覆盖,值可以重复,里面的元素无序。
3)添加元素的方法
ArrayList用add(Object object)方法添加元素,而HashMap用put(Object key, Object value)添加元素。
4)默认的大小和扩容
在 Java 7 中,ArrayList的默认大小是 10 个元素,HashMap 的默认大小是16个元素(必须是2的幂)。
06. 多线程创建方式有哪几种(具体创建过程是什么)
1.继承thread 类,重写run方法,然后new Thread().start启动线程,也可以直接匿名内部类的方式创建
new Thread(
public void run(){
};
).start;
在里边写run方法的实现
2.实现runnable接口,重写run方法
3.实现callable接口(一般很少用)
07. 多线程的常见应用场景:
1、后台定时任务,例如:定时向大量(100w以上)的用户发送邮件;
2、异步处理,例如:发微博、记录日志等;
3、分布式计算消息队列
08. 线程有哪几种状态
1.创建状态 刚被new Thread()
2.就绪状态 准备好了run方法,等待cpu
3.运行状态 running
4.阻塞状态(包括sleep、wait(notify)、suspend(resume)、以及没抢到锁)
5.死亡状态
09. 线程池初始化时有哪些参数可以设置
一般tomcat线程池不用自己配,自己写线程池的话是需要自己配置参数的
那 线程初始化时设置参数的格式是:
private static final int corePoolSize = xxx;
创建线程池对象时,将配置的各种参数用逗号连接传参进去。
ThreadPoolExecutor mExecute = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue,
threadFactory,
rejectHandler
);
各个参数代表的意义:
corePoolSize:线程池的核心线程数。在没有设置 allowCoreThreadTimeOut 为 true 的情况下,核心线程会在线程池中一直存活,即使处于闲置状态。
maximumPoolSize:线程池所能容纳的最大线程数。大于这个数调用任务拒绝handler
keepAliveTime:非核心线程闲置时的超时时长。超过该时长,非核心线程就会被回收。
unit:keepAliveTime 时长对应的单位。
workQueue:线程池中的任务队列,当有提交的任务暂时没有足够的线程去执行的时候,就会进入workQueue等待
rejectHandler:拒绝策略,当线程池中线程数大于maximumPoolSize,且任务队列也排满了,如何拒绝任务。
JDK给我们内置了四种拒绝策略:直接抛出异常、丢弃最老的一个任务然后重新提交当前任务、放弃无法执行的任务,然后当做无事发生、还有一种没看懂就不写出来了
10. 线程池的种类(4种)区别和使用场景
首先,不同线程池之间的区别就是他们新建时传入的参数值不一样(新建方法是一样的)
1.newFixedThreadPool,线程数量固定的线程池,线程池的corePoolSize和maximumPoolSize大小一样,并且keepAliveTime为0,传入的队列LinkedBlockingQueue为无界队列
2.newSingleThreadExecutor,单线程池,corePoolSize和maximumPoolSize都是1,keepAliveTime是0
3.newCachedThreadPool,可缓存线程池,说到缓存一般离不开过期时间,该线程池也是,corePoolSize设置为0,maximumPoolSize设置为int最大值,不同的是,线程池传入的队列是SynchronousQueue,一个同步队列,该队列没有任何容量,每次插入新数据,必须等待消费完成。当有新任务到达时,线程池没有线程则创建线程处理,处理完成后该线程缓存60秒,过期后回收,线程过期前有新任务到达时,则使用缓存的线程来处理。
4.newScheduledThreadPool,这个线程池使用了ScheduledThreadPoolExecutor,该线程池继承自ThreadPoolExecutor, 执行任务的时候可以指定延迟多少时间执行,或者周期性执行。
11. ==和equals有什么区别?
对基本数据类型 ==比较的是值,引用类型 ==比较的是地址
equals比较的大多是地址,但是String和Integer对其进行了重写,所以比较的是值
12. Thread类中的start()和run()方法有什么区别
start启动线程,run方法只是thread的一个普通方法,就算调用了也还是在主线程里执行
同步有几种实现方法?
同步的实现方面有两种,使用synchronized同步锁、volatile关键字、lock锁对象的lock()和unlock()方法
volatile关键字
Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”
锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)。
互斥指一个线程拿到了锁,其他线程就必须等待完成。
可见性要表示一个线程改完了一个公共数据(实际上是先改自己的缓存数据,然后同步到公共数据上,然后另外的线程看到公共数据变了,将变换的值同步到自己的缓存,这个过程有好几部,所以会有线程安全问题),必须要保证其他线程知道数据改变了
使用 volatile 变量的主要原因用法简单,在公共数据上加一个volatile关键字就行,其次是性能优于sychronize同步锁
线程产生死锁的原因和解决办法:
什么是死锁:打个比方,假设有P1和P2两个进程,都需要A和B两个资源,现在P1持有A等待B资源,而P2持有B等待A资源,两个都等待另一个资源而不肯释放资源,就这样无限等待中,这就形成死锁
定义:如果一组进程中每一个进程都在等待仅由该组进程中的其他进程才能引发的事件,那么该组进程是死锁的。
产生死锁原因:一种原因是系统提供的资源太少了,远不能满足并发进程对资源的需求。这种竞争资源引起的死锁是我们要讨论的核心;
另一种原因是由于进程推进顺序不合适引发的死锁。资源少也未必一定产生死锁。就如同两个人过独木桥,如果两个人都要先过,在独木桥上僵持不肯后退,必然会应竞争资源产生死锁;但是,如果两个人上桥前先看一看有无对方的人在桥上,当无对方的人在桥上时自己才上桥,那麽问题就解决了。所以,如果程序设计得不合理,造成进程推进的顺序不当,也会出现死锁。
解决死锁问题的三种方法:预防死锁、检测死锁及避免死锁。
解决办法:预防死锁的发生往往需要很大的系统开销,而且不能充分利用资源,为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段
核心思想:打破线程间的相互等待状态,比如
1.找到相互等待的线程的spid,kill掉
2.使用sql server 内部的锁监视器线程执行死锁检查,当检测到死锁时,回滚事务以及该事务持有的锁,使得其他线程得以正常运行
多线程有几种实现方法?
多线程有三种实现方法,分别是继承Thread类、实现Runnable接口、实现Callable接口
Callable和Runnable的区别是什么
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以
(4)运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如果线程没有执行完,Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常,Future.get()会throws InterruptedException或者ExecutionException;如果线程已经取消,会跑出CancellationException。取消由cancel 方法来执行。isDone确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明Future<?> 形式类型、并返回 null 作为底层任务的结果。
IO流,了解常见的几个流对象以及基本的流操作即可
数组集合
什么是连接池,为什么使用连接池
什么是接口隔离?
接口跟抽象类的区别?
hashcode和equal的区别
hashmap和hashtable的区别是什么?
hashmap实现原理,扩容因子过大过小的缺点,扩容过程
ArrayList和linkenList的区别?
java地址和值传递的例子
值传递:只传递值,各是各的
引用传递:传递地址,共同操作这个值
Linux常用命令列举10个
ls/ll 显示文件夹下所有文件/详细显示
pwd 查看当前目录的绝对路径
cd 切换目录
ps 查看进程
kill 杀死进程
mv 移动文件
mkdir 创建文件夹
rmdir 删除文件夹
touch 创建文件
tar zxvf 解压
date 显示日期
cal 显示日历
vi 用vim编辑文件
clear 清屏
synchronized实现原理
synchronizated和lock差别?
java Nio
是否可以继承String类?
String类是final类故不可以继承。
几种线程暂停
a. wait():使一个线程处于等待状态,并且释放持有的锁
b. sleep():使一个正在运行的线程处于睡眠状态,时间过了自动会醒,所以不释放锁
c. notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确
切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
d. allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
启动一个线程是用run()还是start()?
启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。
SOCKET套接字中有几中连接方式,各有什么区别?
Sockets有两种主要的操作方式:面向连接(TCP/IP)的和无连接(UDP)的。无连接的操作使用数据报协议,无连接的操作是快速的和高效的,但是数据安全性不佳. 面向连接的操作使用TCP协议.面向连接的操作比无连接的操作效率更低,但是数据的安全性更高
sleep()和wait()区别
sleep() 方法:线程主动放弃CPU,使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。典型地,sleep() 被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。
wait( ) :与notify()配套使用,wait()使得线程进入阻塞状态,它有两种形式,一种允许指定以毫秒为单位的一段时间作为参数,另一种没有参数,当指定时间参数时对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用
hashCode方法的作用?
hashcode这个方法是用来鉴定2个对象是否相等的。hashcode方法一般用户不会去调用,比如在hashmap中,由于key是不可以重复的,他在判断key是不是重复的时候就判断了hashcode这个方法,而且也用到了equals方法。这里不可以重复是说equals和hashcode只要有一个不等就可以了!所以简单来讲,hashcode相当于是一个对象的编码。我们一般在覆盖equals的同时也要覆盖hashcode,让他们的逻辑一致。
简述synchronized和java.util.concurrent.locks.Lock的异同 ?
主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。
Java字节码的执行有两种方式:
1)即时编译方式:解释器先将字节编译成机器码,然后再执行该机器码。 2)解释执行方式:解释器通过每次解释并执行一小段代码来完成java字节 码程序的所有操作。
Java四种引用包括强引用,软引用,弱引用,虚引用
2.获取Class的方式有哪些
方式一:对象.getClass()
Student student = new Student();
student.getClass();
方式二:类名.Class
Student.Class
方式三:Class.forname("完整的类路径.包名.类名")
3.int和Integer的区别
基础答案:Ingeter是int的包装类,int的初值为0,Ingeter的初值为null。
进阶答案:Ingeter将-128-127进行缓存,因此
4.ArrayList和LinkedList的区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
5.==和equals的区别
1)对于==,比较的是值是否相等
如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址
2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
6.override和overload的比较
重载Overload:在同一个类中,允许存在一个以上的同名函数,只要他们的参数个数或者参数类型不同即可。
重载的特点:与返回值类型无关,只看参数列表。
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中定义的方法,这相当于把父类中定义的那个完全相同的方法给覆盖掉了,这也是面向对象编程的多态的一种表现。子类覆盖父类方法时只能抛出父类的异常或者异常的子类或者父类异常的子集,因为子类可以解决父类的一些问题,但不能比父类有更多的问题。还有,子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是private类型,则子类中根本不存在覆盖,即子类中和父类的private的同名的方法没有覆盖的关系,因为private的访问权限只限于同一类中,而子类就不会访问到private的方法,所以是子类中增加的一个全新的方法
7.简述servlet生命周期
(1)加载和实例化
当Servlet容器启动或客户端发送一个请求时,Servlet容器会查找内存中是否存在该Servlet实例,若存在,则直接读取该实例响应请求;如果不存在,就创建一个Servlet实例。
(2) 初始化
实例化后,Servlet容器将调用Servlet的init()方法进行初始化(一些准备工作或资源预加载工作)。
(3)服务
初始化后,Servlet处于能响应请求的就绪状态。当接收到客户端请求时,调用service()的方法处理客户端请求,HttpServlet的service()方法会根据不同的请求 转调不同的doXxx()方法。
(4)销毁
当Servlet容器关闭时,Servlet实例也随时销毁。其间,Servlet容器会调用Servlet 的destroy()方法去判断该Servlet是否应当被释放(或回收资源)。
9.farward和redirect区别
转发(Forward),是一次请求,只有一个request,因此request域内的数据可以共享。
重定向(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。
10.final finally finalize区别
Java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize()。
11.乐观锁与悲观锁
悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁 。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized 等独占锁就是悲观锁思想的实现。
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
两种锁的使用场景
冲突真的很少发生的时候,用乐观锁就比较合适。
经常产生冲突,用悲观锁就比较合适。
12.String、StringBuffer和StringBuilder的区别
在线程安全:StringBuilder是线程不安全的,而StringBuffer是线程安全的
运行速度:StringBuilder > StringBuffer > String
13.char可以存储汉字吗为什么
char是按照字符存储的,不管英文还是中文 占用占用2个字节,用来储存Unicode字符 unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。
15.简述HashMap的实现原理
重写HashMap需要重写hashCode()和equals()方法
16.HashMap和HashTable的区别
线程不安全和线程不安全
键值可为null键值不可为null
前者快后者慢
我们能否让HashMap同步?
HashMap可以通过下面的语句进行同步:
Map m = Collections.synchronizeMap(hashMap);
18.a=a+b与a+=b的区别
举例:a为int,b为float 则a = a + b 需要强制类型转换,也就是我们常写的 a = (int) (a+b);
而我们的a += b 被我们的编译器在编译期做了一些小手脚。也就是编译器帮我们进行了强制类型转化。
& 和 &&的区别
&和&&都可以用作逻辑与的运算符
&&还具有短路的功能
&还可以用作位运算符
深拷贝和浅拷贝的区别
打个不太恰当的比喻:一个是复制一份新的 一个是弄了一个快捷方式
Java的八大基本数据类型是什么
byte short int long float double boolean char
进程、线程和协程的区别
1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程
2) 线程进程都是同步机制,而协程则是异步
3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
创建两种线程的方式 他们有什么区别
1.继承Thread类
2.实现Runnable接口
守护线程:守护线程则是用来服务用户线程的,如果没有其他用户线程在运行,那么就没有可服务对象,守护线程就会退出。
Array(数组)和ArrayList(列表)有什么区别
1)精辟阐述:
可以将 ArrayList想象成一种“会自动扩增容量的Array”。
2)Array([]):数组,最高效;但是其容量固定且无法动态改变;
ArrayList: 动态数组,容量可动态增长;但牺牲效率;
Runnable和Callable的区别
编写多线程程序一般有三种方法,Thread,Runnable,Callable.
Runnable和Callable的区别是,
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以
(4)Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
wait(),notify()和suspend(),resume()之间的区别
wait(),notify()有两种形式一种是传入一个时间参数,自动恢复,一种是不传参,不会自动恢复,必须使用notify()方法
suspend(),resume():suspend()方法很容易引起死锁问题,已经不推荐使用了。
default,public,private,protected区别
tomcat调优
声明式事务
接口隔离
代码块、静态代码块执行顺序
Java子父类间静态代码块、非静态代码块、构造方法的执行顺序
子类A继承父类B,A a=new A();
正确的执行顺序是:父类B静态代码块->子类A静态代码块->父类B非静态代码块->父类B构造函数->子类A非静态代码块->子类A构造函数
也就是说非静态初始化块的执行顺序要在构造函数之前。
如何捕获子线程异常
线程设计的理念:“线程的问题应该线程自己本身来解决,而不要委托到外部。”
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。