前言/背景
据说今年面试压力特别大,不知真假~
不管面试压力大不大,复习好,该掌握的技术点都熟练掌握,珍惜每一次面试机会
今天给大家分享一篇基础的面试题,不要输在这些基础且又常见的问题上
资料总结/刷题指南
这里先自荐一个面试刷题的小程序吧,大家可以免费去刷题,希望可以帮助到你。
大家可以扫码前往,也可以微信搜索【Java面试 | 笑小枫】小程序。持续更新中,后续会上一些资源、简历模板、面试分享内容
面试流程
老面👴:&和&&有什么区别?
笑小枫🍁:&可用于位运算,当左右两边的条件不是布尔型,而是数字时,它会进行位运算;
当&运算符两侧是是布尔型,且表达式的结果均为真时,整个运算结果才为真;当&&操作符第一个表达式为 false时,结果为 false,并且不再计算第二个表达式,具有短路功能。
老面👴:||、&&、! 有什么区别?
笑小枫🍁:‘||’是 逻辑或的意思,就是或者,有一个对的就是对的。a||b,表示a表达式或b表达式有一个返回true,则a||b整个表达式返回true。
例:
1==1 || 1==1 //返回true
1==1 || 1==2 //返回true
1==2 || 1==2 //返回false
‘&&’是逻辑且的意思,就是并且,有一个是错的就是错的。a&&b,表示a表达式或b表达式有一个返回false ,则a&&b整个表达式返回false。如果a表达式为false,则直接返回false,不会再判断b表达式。
例:
1==1 && 1==1 //返回true
1==1 && 1==2 //返回false
1==2 && 1==2 //返回false
‘!’是逻辑非的意思,就是反转,原来是的对的,加上!后,就变成错的,原来是错的,加上!后,就变成了对的。
!true 返回false
!false 返回true
例:
! (1==1) //返回false
! (1==2) //返回true
老面👴:== 与 equals有什么区别?
笑小枫🍁:可以从功能、定义和运行速度上来说:
- 功能不同
== 既可以比较基本类型也可以比较引用类型;对于基本类型,== 比较的是值;对于引用类型,== 比较的是地址;
equals不能用于基本类型的比较;如果没有重写equals,equals就相当于==;如果重写了equals方法,equals比较的是对象的内容。
注意:重写equals方法的同时,也要重写hashCode,不然同一个对象比较,可能会出现hashCode不同,equals比较的时候先判断hashCode是否相同,然后再比较值,如果hashCode不同,则直接认为这两个对象不同。
- 定义不同
equals在JAVA中是一个方法;== 在JAVA中只是一个运算符合。 - 运行速度不同
== 比equals运行速度快,因为 == 只是比较引用。
老面👴:String、StringBuffer 和 StringBuilder 有什么区别?
笑小枫🍁:可以从可变性、线程安全性、性能三方面来说:
- 可变性
String 类中使用 final 关键字字符数组保存字符串,所以 String 对象是不可变的。而 StringBuilder 与StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串 char[]value 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
- 线程安全性
String 中的对象是不可变的,也就可以理解为常量,线程安全。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
- 性能
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结:
- 操作少量的数据 = String
- 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
- 多线程操作字符串缓冲区下操作大量数据 = StringBuffer
老面👴:final、finally、finalize 有什么区别?
笑小枫🍁:final可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写
finally用于抛异常,finally代码块内语句无论是否发生异常,都会在执行finally,常用于一些流的关闭。
finalize方法用于垃圾回收。
一般情况下不需要我们实现finalize,当对象被回收的时候需要释放一些资源,比如socket链接,在对象初始化时创建,整个生命周期内有效,那么需要实现finalize方法,关闭这个链接。
但是当调用finalize方法后,并不意味着gc会立即回收该对象,所以有可能真正调用的时候,对象又不需要回收了,然后到了真正要回收的时候,因为之前调用过一次,这次又不会调用了,产生问题。所以,不推荐使用finalize方法。
老面👴:throw 和 throws 有什么区别?
笑小枫🍁:
throw作用在方法内,表示抛出具体异常,由方法体内的语句处理; 一定抛出异常;
throws作用在方法的声明上,表示抛出异常,由调用者来进行异常处理; 可能出现异常,不一定会发生异常。
老面👴:Error 和 Exception 有什么区别?
笑小枫🍁:
Error表示系统级的错误和程序不必处理的异常;比如内存溢出、线程死锁、虚拟机错误等;
Exception表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况;比如IO异常、Sql异常、运行时异常等。
老面👴:BIO、NIO、AIO 有什么区别?
笑小枫🍁:
BIO:Block IO同步阻塞式IO,就是我们平常使用的传统IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO同步非阻塞IO,是传统IO的升级,客户端和服务器端通过Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO是NIO的升级,也叫NIO2,实现了异步非堵塞IO,异步IO的操作基于事件和回调机制。
BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。
BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
老面👴:重载(Overload)和重写(Override)有什么区别?
笑小枫🍁:
重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
PS:注意这里是类,如果是接口,比如我们常用的serviceImpl实现service接口,然后方法上会用@Override
注解,但这并不是重写,而是实现的一种方式。重写是类之间的继承extends
。
老面👴:成员变量与局部变量有什么区别?
笑小枫🍁:
- 从语法形式上,成员变量是属于类的,局部变量是在方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 修饰;
- 从变量在内存中的存储方式来看,成员变量是对象的一部分,而对象存在于堆内存,局部变量存在于栈内存;
- 从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失;
- 成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外被 final 修饰的成员变量必须显示地赋值);而局部变量则不会自动赋值。
老面👴:静态方法和实例方法有什么区别?
笑小枫🍁:
- 在外部调用静态方法时,可以使用”类名.方法名”的方式,也可以使用”对象名.方法名”的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
- 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。
老面👴:#{}和${}的区别是什么?
笑小枫🍁:
#{}是预编译处理,${}是字符串替换;使用#{}可以有效的防止SQL注入。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。例如传入表名、SQL片段,排序字段等场景。存在sql注入问题,请谨慎使用!
老面👴:线程的run()和start()有什么区别?
笑小枫🍁:
start() 方法用于启动线程,run() 方法用于执行线程的运行时代码。run() 可以重复调用,而 start() 只能调用一次。
start()方法来启动一个线程,真正实现了多线程运行。调用start()方法无需等待run方法体代码执行完毕,可以直接继续执行其他的代码; 此时线程是处于就绪状态,并没有运行。 然后通过此Thread类调用方法run()来完成其运行状态, run()方法运行结束, 此线程终止。然后CPU再调度其它线程。
run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的。 如果直接调用run(),其实就相当于是调用了一个普通函数而已,直接待用run()方法必须等待run()方法执行完毕才能执行下面的代码,所以执行路径还是只有一条,根本就没有线程的特征,所以在多线程执行时要使用start()方法而不是run()方法。
老面👴:Synchronized 和 ReentrantLock 区别是什么?
笑小枫🍁:
- 实现原理上
synchronized
是依靠jvm
以及配合操作系统来实现,是一个关键字。 reentrantLock
是jdk1.5
之后提供的API层面的互斥锁。
- 使用便利性上
synchronized
只需要添加上相关关键字即可,加锁与释放过程由操作系统完成。 reentrantLock
则需要手动加锁与释放锁。
- 锁粒度与灵活度
reentrantLock
要强于synchronized
reentrantLock
提供了三个高级功能:
-
等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过
lock.lockInterruptibly()
来实现这个机制。 - 多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,
ReentrantLock
默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。 - 一个
ReentrantLock
对象可以同时绑定对个对象。ReenTrantLock
提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
- 性能区别
synchronized
优化之后性能与reentrantLock
已经不相上下了,官方甚至更建议使用synchronized
关键字。
老面👴:get 和 post 请求有哪些区别?
笑小枫🍁:
- get请求参数是连接在url后面的,而post请求参数是存放在request body内的;
- get请求因为浏览器对url长度有限制,所以参数个数有限制,而post请求参数个数没有限制;
- 因为get请求参数暴露在url上,所以安全方面post比get更加安全;
- get请求只能进行url编码,而post请求可以支持多种编码方式;
- get请求参数会保存在浏览器历史记录内,post请求并不会;
- get请求浏览器会主动cache,post并不会,除非主动设置;
- get请求产生1个tcp数据包,post请求产生2个tcp数据包;
- 在浏览器进行回退操作时,get请求是无害的,而post请求则会重新请求一次;
- 浏览器在发送get请求时会将header和data一起发送给服务器,服务器返回200状态码,而在发送post请求时,会先将header发送给服务器,服务器返回100,之后再将data发送给服务器,服务器返回200 OK。
老面👴:forward 和 redirect 的区别?
笑小枫🍁:
- forward是直接请求转发;redirect是间接请求转发,又叫重定向。
- forward,客户端和浏览器执行一次请求;redirect,客户端和浏览器执行两次请求。
- forward,经典的MVC模式就是forward;redirect,用于避免用户的非正常访问。(例如用户非正常访问,servlet就可以将HTTP请求重定向到登录页面)。
- forward,地址不变;redirect,地址改变。
- forward常用方法:RequestDispatcher类的forward()方法;redirect常用方法:HttpServletRequest类的sendRedirect()方法。
老面👴:session 和 cookie 有什么区别?
笑小枫🍁:
- 存储位置不同
- cookie在客户端浏览器;
- session在服务器;
- 存储容量不同
- cookie
- session没有上线,出于对服务器的保护,session内不可存过多东西,并且要设置session删除机制;
- 存储方式不同
- cookie只能保存ASCII字符串,并需要通过编码方式存储为Unicode字符或者二进制数据;
- session中能存储任何类型的数据,包括并不局限于String、integer、list、map等;
- 隐私策略不同
- cookie对客户端是可见的,不安全;
- session存储在服务器上,安全;
- 有效期不同
- 开发可以通过设置cookie的属性,达到使cookie长期有效的效果;
- session依赖于名为JESSIONID的cookie,而cookie JSESSIONID的过期时间默认为-1,只需关闭窗口该session就会失效,因而session达不到长期有效的效果;
- 跨域支持上不同
- cookie支持跨域;
- session不支持跨域。
寄语
本文到此就结束了,希望本文可以帮助到你,希望你可以找到一个满意的工作
如果需要简历模板或者进行面试指导,可以关注【笑小枫】公众号私聊我哈
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net