深圳店小秘Java后端面试
1.笔试
1.JDK
、JVM
、JRE
、JIT
是什么?
JDK
:Java Development Kit
。是Java
开发工具包,提供Java
编程语言内库。JVM
:Java Virtual Machine
。是Java
虚拟机,将.java
文件加载为.class
文件,并使Java
程序运行。JRE
:Java Runtime Environment
。是Java
运行时环境。JIT
:Just In Time Compliaction
。Java
即时编译器,将Java
对应的字节码文件转换为机器码文件。
2.session
是什么,session
和cookie
的关联是什么?
cookie
可以存储在本地或者浏览器,session
只能存储在服务端。cookie
只能存储String
字符串,session
可以存储任意Java
对象。cookie
没有session
安全,因为前者在客户端,后者在服务端。cookie
存在于客户端,不会占用服务器性能,session
存在于服务端,session
过多会给服务器造成压力。cookie
最大不能超过4k
,浏览器会限制一个网站的cookie
存储数量,一般为20个。session
没有大小限制只与服务器内存相关。
3.Erro
和Exception
的区别是什么?
Error
和Exception
都是Throwable
的子类, 在Java
中只有Throwable
类型的实例才可以被抛出或者捕获,它是异常处理机制的基本类型。
Erroe
和Exception
体现了Java
平台设计者针对不同异常情况的分类,Exception
是程序正常运行中,可以预料到的意外情况,可以被捕获并进行相应的处理。
Error
是指正常情况下,不大可能出现的情况,绝大部分的Error
都会导致程序处于非正常的,不可恢复的状态,不需要捕获,因为就算你捕获到了也没任何意义。常见的OutOfMemoryError
是Error
的子类.
Exception
分为可检查异常checked
和不可检查异常unchecked
。可检查异常在源代码里必须显式的进行捕获处理,这是编译期检查的一部分,不可检查异常是指运行时异常,比如NullPointerException
、ArrayIndexOutOfBoundsException
之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。
其实不需要回答这么多。我的回答就是:
Error
会导致程序处于非正常,不可恢复的状态。
4.什么是GC
?为什么有GC
?调用GC
的方法有哪几种?
GC
:Garbage Collection
,字面意思是垃圾回收。
Java
中每创建一个对象就会在JVM
中的堆内存中为对象开辟一段内存空间用于存储该对象。由于Java
中大多对象的存活期都很短,而JVM
的堆内存并不是无限大的,堆内存的大小是有限的。所以当堆内存被使用完时,而又有创建新生对象的需求,此时堆内存中可用空间不足以为新生对象分配内存,此时就需要对堆内存进行垃圾回收也就是GC
,将系统中不再使用的Java
对象当作垃圾回收掉,释放占用的堆内存空间为后续新生对象使用。JVM
采用分代收集策略进行垃圾回收,对于新生代有MinorGC
,对于老年代有Major GC
,对于整堆有Full GC
。
System.gc();
Runtime.getRuntime.gc();
java.lang.management.MemeoryMXBean.gc();
熟悉
JVM
堆相关的,这一块基本没难度,用自己的话概括一下就行,面试官也不会仔细看,因为看还不如直接问你问题来的直接。
5.String
和StringBuffer
的区别是什么?
String
:被final
修饰,不可变字符串。StringBuffer
:可变字符串,线程安全,效率低于StringBuilder
。
6.String s = new String("xyz")
创建了几个String Object
?
- 当在
JVM
堆中的字符串常量池中存在xyz
时,只会在对上创建一个s
字符串对象。此时创建一个String Object
。 - 当在
JVM
堆中的字符串常量池中不存在xyz
时,会在堆上的字符串常量池中创建一个xyz
字符串对象,然后在堆中创建一个s
字符串对象,并将s
字符串对象中的值引用指向字符串常量池中的zyx
字符串对象。此时创建两个String Object
。
7.Math.round(11.5)
与Math.round(-11.5)
的结果
// 坐标轴向下取整
Math.round(11.5) = 12;
Math.round(-11.5) = -11;
8.final
、finally
、finalize
分别有什么意义?
final
:可修饰字段、方法、类。修饰字段表示该字段不可变,修饰方法表示该方法不能被重写覆盖,修饰类表示该类不可继承。
finally
:配置try...catch...finally
使用的代码块。
finalize
:在对象被回收之前,显式调用用于释放一些资源。对于每个即将回收的对象,JVM
都会调用一次finalize
方法。
9.Abstract Class
和interface
的区别
- 抽象类可以提供成员方法的具体实现,而接口中只能定义方法签名不能定义方法体。
- 抽象类中的成员变量可以为任意类型的变量,而接口中的变量只能为
public static final
常量。 - 抽象类中可以存在静态代码块和静态方法,而接口中不能。
- 一个类只能继承一个抽象类,但是却可以实现多个接口。
10.Java
实现线程的方式有哪几种?
- 继承
Thread
类,重写run()
方法。 - 实现
Runnable
接口,重写run()
方法。 - 实现
Callable
接口,重写call()
方法。 - 使用
Executors
类提供的静态方法。
11.以下代码输出结果是什么?
public class A {
static {
System.out.println("Hello Word!");
}
public static void main(String[] args) {
A a = new A();
a = new A();
}
}
输出Hello Word!
。
非常简单,因为一个类的静态代码块只会在类加载时器的
Linking
链接中的parpare
准备阶段中执行一次,可以理解为静态先行。
12.以下代码输出结果是什么?
public class IntegerTest {
public static void main(String[] args) {
Integer a = new Integer(155);
Integer b = new Integer(155);
if (a == b) {
System.out.println(true);
System.out.println(true);
}
}
}
无任何输出。
这个原因其实也很简单,因为
Java
中大多数的基本数据类型都开启了享元模式,Integer
类中有一个IntegerCache
静态内部类,IntegerCache
类会在类中维护一个cache
数组,用于存Java
默认创建的-128 ~ 127
对象。在[-128, 127]
范围内的整型变量,Integer
类会默认从IntegerCache.cache[]
中根据数组下标获取,而不会去堆中创建一个新的Integer
对象。当超出[-128, 127]
这个范围的整型,Integer
才会在堆中new
一个对象。
Java
的8
种基本数据类型的包装类除了Float
和Double
没有实现常量池,其余的类型都实现了。
13.什么是数据库事务?
事务是数据库中最小的执行单元。作为单个逻辑单元执行的一系列操作的集合,它不可分隔,这些操作会一起像数据库操作系统提交,要么都执行,要么都不执行。
14.什么是索引?索引的缺点是什么?有哪些索引?你用过哪些索引?
索引是一种特殊的数据存储结构,能够加快数据检索的速度。
缺点是索引需要维护,维护索引需要额外的时间与性能开销。同时也会占用物理内存。
主键索引、辅助索引、唯一索引、覆盖索引。
使用过主键索引、联合索引、唯一索引(不推荐使用,在写数据时不能使用change buffer
)、覆盖索引、索引下推。
15.现在有一个表A(name, email)
,查询出表A
中的name
以及name
重复的次数,按照重复次数从大到小取前10条
SELECT
a.name,
COUNT(a.name) num
FROM
a a
GROUP BY
a.name
ORDER BY
COUNT(a.name) DESC
LIMIT 10;
--
SELECT
t.name,
t.num
FROM
(SELECT
a.name,
COUNT(a.name) num
FROM
a a
GROUP BY
a.name) t
ORDER BY
t.num DESC
LIMIT 10;
16.写出你熟悉的key/value
数据库
redis
实话实说,我就只用过
redis
的key/value
数据库。不要给自己挖坑,会什么写什么。
17.常用Linux
命令
rm -rf 删除
touch ${filename} 创建文件
vim ${filename} 查看文件
i 进入插入模式
ESC 退出
:wq 保存退出
:q! 不保存退出
:q 不保存退出
cat ${filename} 查看文件的最后一页
more ${filename} 从第一页开始查看文件内容, 按回车键一行一行进行查看, 按空格键一页一页进行查看, q退出
less ${filename} 从第一页开始查看文件内容, 按回车键一行一行的看, 按空格键一页一页的看, 支持使用PageDown和PageUp翻页, q退出
tail -f ${filename} 查看文件的后10行
head -f ${filename} 查看文件的前10行
tail -n 7 ${filename} 查看文件的后7行
head -n 7 ${filename} 查看文件的前7行
sed -i '1d' ${filename} 删除文件第一行
sed -i '2d' ${filename} 删除文件第二行
grep ${keyword} ${filename} 在文件中搜索keyword字符串,大小写敏感,显示行
grep -n ${keyword} ${filename} 在文件中搜索keyword字符串,大小写敏感,显示行及行号
grep -v ${keyword} ${filename} 在文件中搜索keyword字符串,大小写敏感,显示没搜索到的行
grep -i ${keyword} ${filename} 在文件中搜索keyword字符串,大小写敏感,显示行
grep -ni ${keyword} ${filename} 在文件中搜索keyword字符串,大小写敏感,显示行及行号
head -n 10000 ${filename} > ${filename1} 复制filename文件的前10000行到filename2
18.如何在vi
中删除某一行
dd 删除当前行
ndd 删除n行数据
dG 删除当前行之后的全部行
19.编写一个冒泡排序或者二分排序
public static int[] doBubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {
return arr;
}
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}
return arr;
}
private static void swap(int[] arr, int i, int j) {
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
这里可以使用无进制位相加骚一下。但是使用异或的前提是需要保证两个变量在堆内存中的地址不能为同一个,使用是有前提的,不要骚过头了!!!
20.写出一个单例
public class DCLSingleton {
private DCLSingleton() {}
private static volatile DCLSingleton instance = null;
public static DCLSingleton getInstance() {
if(instance == null) {
synchronized (DCLSingleton.class){
if(instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}
还可以用静态内部类。记得私有化构造器,细节。
21.写出最有效率遍历Map
集合的方法
Map<String, Object> map = new HashMap<>(1 << 4);
map.forEach((key, value) -> {
System.out.println("key is : " + key + " value is : " + value)
});
forEach()
底层使用的是entrySet
进行遍历,所以这就是最有效率最优雅的遍历方式。ps
个人认为。
笔试没难度,就是要花时间写。用电脑用久了,突然一下需要写这么多还是有点不习惯,特别是有些字还忘记了怎么写!!!
笔者笔试后就是HR
面,然后就是部门组长技术面,技术负责人技术面,HR
面。下午两点去的,最后弄完都快六点,说了一下午都没给杯水喝,喉咙都快说破了。面试之前记得自己买瓶水!!!
鉴于本人技术有限,文中难免出现一些错误,感谢大家批评指正。