常见面试题翻车合集
1.去掉 main 方法的 static 修饰符,程序会怎样?
A:程序无法编译
B:程序正常编译,正常运行
C:程序正常编译,正常运行一下马上退出
D:程序正常编译,运行时报错
答:D
题目解析:运行时异常如下:
错误: main 方法不是类 xxx 中的 static, 请将 main 方法定义为:
public static void main(String[] args)
2.以下程序运行的结果是?
1 | public class TestClass { |
A:3
B:2
C:4
D:程序无法编译
答:D
题目解析:局部变量 s 不能使用任何修饰符(private/protected/public)修饰,调用的方法要加上 static,否则编译会报错。
3.以下程序有几处错误?
1 | abstract class myAbstractClass |
A:1
B:2
C:3
D:4
答:C
题目解析:类少一个“{”类开始标签、抽象方法不能包含方法体、抽象方法访问修饰符不能为 private,因此总共有 3 处错误。
4.以下程序执行的结果是?
1 | class A { |
A:程序无法编译
B:程序正常编译,运行报错
C:x=1,y=2
D:x=0,y=1
答:C
5.switch 语法可以配合 return 一起使用吗?return 和 break 在 switch 使用上有何不同?
答:switch 可以配合 return 一起使用。return 和 break 的区别在于 switch 结束之后的代码,比如以下代码:
1 | String getColor(String color) { |
对于以上这种 switch 之后没有特殊业务处理的程序来说,return 和 break 的效果是等效的。然而,对于以下这种代码:
1 | String getColor(String color) { |
如果 switch 之后还有特殊的业务处理,那么 return 和 break 就有很大的区别了。
6.一个栈的入栈顺序是 A、B、C、D、E 则出栈不可能的顺序是?
A:E D C B A
B:D E C B A
C:D C E A B
D:A B C D E
答:C
题目解析:栈是后进先出的,因此:
- A 选项:入栈顺序 A B C D E 出栈顺序就是 E D C B A 是正确的;
- B 选项:A B C D 先入栈,D 先出栈,这个时候 E 在入栈,E 在出栈,顺序 D E C B A 也是正确的;
- C 选项:D 先出栈,说明 A B C 一定已入栈,因为题目说了入栈的顺序是 A B C D E,所以出栈的顺序一定是 C B A,而 D C E A B 的顺序 A 在 B 前面是永远不可能发生的,所以选择是 C;
- D 选项 A B C D E 依次先入栈、出栈,顺序就是 A B C D E。
7.可以在 finally 块中使用 return吗?
答:不可以,finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。
8.FileInputStream 可以实现什么功能?
A:文件夹目录获取
B:文件写入
C:文件读取
D:文件夹目录写入
答:C
题目解析:FileInputStream 是文件读取,FileOutputStream 才是用来写入文件的,FileInputStream 和 FileOutputStream 很容易搞混。
9.以下程序打印的结果是什么?
1 | Thread t1 = new Thread(){ |
答:程序报错 java.lang.IllegalArgumentException,setPriority(n) 方法用于设置程序的优先级,优先级的取值为 1-10,当设置为 0 时,程序会报错。
10.如何设置守护线程?
答:设置 Thead 类的 setDaemon(true) 方法设置当前的线程为守护线程。
守护线程的使用示例如下:
1 | Thread daemonThread = new Thread(){ |
11.以下说法中关于线程通信的说法错误的是?
A:可以调用 wait()、notify()、notifyAll() 三个方法实现线程通信
B:wait() 必须在 synchronized 方法或者代码块中使用
C:wait() 有多个重载的方法,可以指定等待的时间
D:wait()、notify()、notifyAll() 是 Object 类提供的方法,子类可以重写
答:D
题目解析:wait()、notify()、notifyAll() 都是被 final 修饰的方法,不能再子类中重写。选项 B,使用 wait() 方法时,必须先持有当前对象的锁,否则会抛出异常 java.lang.IllegalMonitorStateException。
12.ReentrantLock 默认创建的是公平锁还是非公平锁?
答:默认创建的是非公平锁,看以下源码可以得知:
1 | /** |
Nonfair 为非公平的意思,ReentrantLock() 等同于代码 ReentrantLock(false)。
13.ReentrantLock 如何在一段时间内无阻塞尝试访问锁?
答:使用 tryLock(long timeout, TimeUnit unit) 方法,就可以在一段时间内无堵塞的访问锁。
14.枚举比较使用 equals 还是 ==?
答:枚举比较调用 equals 和 == 的结果是一样,查看 Enum 的源码可知 equals 其实是直接调用了 ==,源码如下:
1 | public final boolean equals(Object other) { |
15.在 Spring 中使用 @Value 赋值静态变量为什么 null?怎么解决?
答:因为在 Springframework 框架中,当类加载器加载静态变量时,Spring 上下文尚未加载,因此类加载器不会在 bean 中正确注入静态类,导致了结果为 null。可使用 Setter() 方法给静态变量赋值,代码如下:
1 |
|
16.如何自己实现一个定时任务?
答:启动一个后台线程,循环执行任务。代码示例如下:
1 | Thread getTocketThread = new Thread(new Runnable() { |
17.如何定义一个不定长度的数组?
答:在 Java 中使用数组必须要指定长度,如果长度不固定可使用 ArrayList、LinkedList 等容器接收完数据,再使用 toArray() 方法转换成固定数组。
18.如何优雅的格式化百分比小数?
答:使用数字格式化类 DecimalFormat 来处理,具体实现代码如下:
1 | double num = 0.37500; |
19.什么是跨域问题?为什么会产生跨域问题?
答:跨域问题指的是不同站点直接,使用 ajax 无法相互调用的问题。跨域问题是浏览器的行为,是为了保证用户信息的安全,防止恶意网站窃取数据,所做的限制,如果没有跨域限制就会导致信息被随意篡改和提交,会导致不可预估的安全问题,所以也会造成不同站点间“正常”请求的跨域问题。
20.跨域的解决方案有哪些?
答:常见跨域问题的解决方案如下:
- jsonp(只支持 get 请求);
- nginx 请求转发,把不同站点应用配置到同一个域名下;
- 服务器端设置运行跨域访问,如果使用的是 Spring 框架可通过 @CrossOrigin 注解的方式声明某个类或方法运行跨域访问,或者配置全局跨域配置,请参考以下代码:
1 | // 单个跨域配置 |
21.什么原因会导致 Nginx 转发时丢失部分 header 信息?该如何解决?
答:部分 header 信息丢失的原因是,丢失的 header 的 key 值中有下划线,因为 Nginx 转发时,默认会忽略带下划线的 header 信息。
解决方案有两个,一是去掉 key 值中的下划线,二是在 Nginx 的配置文件 http 中添加“underscoresinheaders on;” 不忽略有下划线的 header 信息。
22.如何设计一个高效的系统?
答:要设计一个高效的系统,通常要包含以下几个方面。
(1)优化代码
代码优化分为两种情况:
- 代码问题导致系统资源消耗过多的问题,比如,某段代码导致内存溢出,往往是将 JVM 中的内存用完了,这个时候系统的内存资源消耗殆尽了,同时也会引发 JVM 频繁地发生垃圾回收,导致 CPU 100% 以上居高不下,这个时候又消耗了系统的 CPU 资源。这种情况下需要使用相应的排查工具 VisualVM 或 JConsole,找到对应的问题代码再进行优化;
- 还有一种是非问题代码,这种代码不容易发现,比如,LinkedList 集合如果使用 for 循环遍历,则它的效率是很低的,因为 LinkedList 是链表实现的,如果使用 for 循环获取元素,在每次循环获取元素时,都会去遍历一次 List,这样会降低读的效率,这个时候应该改用 Iterator (迭代器)迭代循环该集合。
(2)设计优化
有很多问题可以通过我们的设计优化来提高程序的执行性能,比如,使用单例模式来减少频繁地创建和销毁对象所带来的性能消耗,从而提高了程序的执行性能。
(3)参数调优
JVM 和 Web 容器的参数调优,对系统的执行性能也是也很大帮助的。比如,我们的业务中会创建大量的大对象,我们可以通过设置,将这些大对象直接放进老年代,这样可以减少年轻代频繁发生小的垃圾回收(Minor GC),减少 CPU 占用时间,从而提升了程序的执行性能。Web 容器的线程池设置以及 Linux 操作系统的内核参数设置,也对程序的运行性能有着很大的影响,我们根据自己的业务场景优化这两项内容。
(4)使用缓存
缓存的使用分为前端和后端:
- 前端可使用浏览器缓存或者 CDN,CDN 的全称是 Content Delivery Network,即内容分发网络。CDN 是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN 的关键技术主要有内容存储和分发技术;
- 后端缓存,使用第三方缓存 Redis 或 Memcache 来缓存查询结果,以提高查询的响应速度。
(5)优化数据库
数据库是最宝贵的资源,通常也是影响程序响应速度的罪魁祸首,它的优化至关重要,通常分为以下六个方面:
- 合理使用数据库引擎
- 合理设置事务隔离级别,合理使用事务
- 正确使用 SQL 语句和查询索引
- 合理分库分表
- 使用数据库中间件实现数据库读写分离
- 设置数据库主从读写分离
(6)屏蔽无效和恶意访问
前端禁止重复提交:用户提交之后按钮置灰,禁止重复提交;
用户限流,在某一时间段内只允许用户提交一次请求,比如,采取 IP 限流。
(7)搭建分布式环境,使用负载分发
可以把程序部署到多台服务器上,通过负载均衡工具,比如 Nginx,将并发请求分配到不同的服务器,从而提高了系统处理并发的能力。