0%

【面试】Java高频面试题(尚硅谷)

关于Java高频面试题学习


1 JavaSE

1.1 自增变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void test01() {
/*
考点:i++,先赋值,再自增;++i,先自增,再赋值
运算结果:i=4,j=1,k=11
*/
int i=1;
i = i++; // i是先赋值给i,所以i仍然是1
int j = i++; // j=1,再i自增,i=2
int k = i + ++i * i++; // k = 2 + 3 * 3 = 11,结束赋值后i++自增1
System.out.println("i=" + i);
System.out.println("j=" + j);
System.out.println("k=" + k);
/*
总结:
赋值=,最后计算
=右边的从左到右加载值一次压入操作数栈
按照运算符优先级计算
自增、自减操作都是直接修改变量的值,不经过操作数栈
最后的复制之前,临时结果也是存储在操作数栈中
*/
}

1.2 单例模式

  • 饿汉式:直接创建对象,不存在线程安全问题(3种)
1
2
3
4
5
6
7
8
9
10
11
public class Singleton1 {
/*
要点(懒汉式):
1、构造器私有化
2、自行创建,并用静态变量保存实例
3、向外提供实例(public 或 自定义get方法)
4、强调是单例,可以用final进行修饰
*/
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1() {}
}
1
2
3
4
5
6
public enum Singleton2 {
/*
枚举类只定义一个,即为单例
*/
INSTANCE;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Singleton3 {
/*
跟直接实例化懒汉式基本一致,但使用场景不同
使用场景:
实例化带有参数,而且参数是从配置文件动态获取时
*/
public static final Singleton3 INSTANCE;

static {
// 配置文件动态获取info(这里直接写死)
String info = "Hello World!";
INSTANCE = new Singleton3(info);
}

private String info;
private Singleton3(String info) {
this.info = info;
}
}
  • 懒汉式:延迟创建对象(3种)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Singleton4 {
/*
要点:
1、私有构造器
2、私有静态变量实例
3、提供静态方法获取实例(实例为null,则创建,反之返回实例)
【多线程存在线程安全问题】
*/
private static Singleton4 instance;

private Singleton4() {}

public static Singleton4 getInstance() {
if (instance == null) {
// 若此部分执行代码过长,会导致其他线程运行时,发现实例不存在,也会进入此判断
instance = new Singleton4();
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Singleton5 {
/*
加入同步锁,解决线程安全
外层加多一层判断,提供性能
*/
private static Singleton5 instance;

private Singleton5() {}

public static Singleton5 getInstance() {
if (instance == null) {
// 加入同步锁,保证线程安全
synchronized (Singleton5.class) {
if (instance == null) {
instance = new Singleton5();
}
}
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton6 {
/*
1、内部类被加载时才会创建INSTANCE实例(内部类加载就会有此INSTANCE,不存在INSTANCE为null,重新new的情况)
2、静态内部类不会随外部类加载而进行初始化,需要单独加载和初始化
3、因为是在内部类加载和初始化时创建的,因此是线程安全的
*/
private Singleton6() {}

private static class Inner {
private static final Singleton6 INSTANCE = new Singleton6();
}

public static Singleton6 getInstance() {
return Inner.INSTANCE;
}
}

1.3 类初始化和实例化过程

  • (1)类初始化过程
    • main函数所在类先初始化
    • 子类初始化需要先初始化父类
    • 按代码顺序执行静态类变量、静态代码块
  • (2)类实例化过程
    • 子类实例化需要先实例化父类
    • 按代码顺序执行非静态变量、非静态代码块
    • 构造器永远最后执行
  • (3)重写
    • 子类重写父类方法,父类调用方法时是调用子类的重写方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 父类
public class Father {

private int i = test();

private static int j = method();

static {
System.out.print("(1)");
}

Father() {
System.out.print("(2)");
}

{
System.out.print("(3)");
}

public int test() {
System.out.print("(4)");
return 1;
}

public static int method() {
System.out.print("(5)");
return 1;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
1、main所在类进行初始化
(1)先初始化Father
静态变量 j = method(),没被重写,【(5)】
静态代码块 【(1)】
(2)再初始化Son
静态变量 j = method(),【(10)】
静态代码块 【(6)】

2、"Son s1 = new Son();"类实例化
(1)先实例化Father
非静态变量 i = test(),方法被重写,【(9)】
非静态代码块 【(3)】
构造器 【(2)】
(2)再实例化Son
非静态变量 i = test(),【(9)】
非静态代码块 【(8)】
构造器 【(7)】

总运行结果为:(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
*/
public class Son extends Father{

private int i = test();

private static int j = method();

static {
System.out.print("(6)");
}

Son() {
System.out.print("(7)");
}

{
System.out.print("(8)");
}

@Override
public int test() {
System.out.print("(9)");
return 1;
}

// 重载(非重写,static不能重写)
public static int method() {
System.out.print("(10)");
return 1;
}

public static void main(String[] args) {
Son s = new Son(); // (5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
}
}

1.4 传参机制

  • 基本数据类型:传递值
  • 引用数据类型:传递地址值
  • String和包装类:无法修改值,改变值需要新创空间,重新指向新空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ParamTest {
public static void main(String[] args) {
int i = 1;
String str = "hello";
Integer num = 200;
int[] arr = {1, 2, 3, 4};
MyData my = new MyData();

change(i, str, num, arr, my);

System.out.println("i = " + i); // i = 1 (基本数据类型)
System.out.println("str = " + str); // str = hello (无法修改值)
System.out.println("num = " + num); // num = 200 (无法修改值)
System.out.println("arr = " + Arrays.toString(arr)); // arr = [2, 2, 3, 4] (引用数据类型)
System.out.println("my.a = " + my.a); // my.a = 11 (引用数据类型)
}

static class MyData {
int a = 10;
}

public static void change(int i, String str, Integer num, int[] arr, MyData my) {
i += 1;
str += "world";
num += 1;
arr[0] += 1;
my.a += 1;
}
}

1.5 递归和迭代

  • 递归:
    • 优点:大问题转化为小问题,可以减少代码量,同时代码精简,可读性好
    • 缺点:递归调用浪费了空间,而且递归太深容易造成堆栈溢出
  • 迭代:
    • 优点:代码运行效率好,因为时间只因循环次数增加而增加,而且没有额外的空间开销
    • 缺点:代码不如递归简洁,可读性差
1
2
3
4
5
6
7
8
9
/*
编程题:有n步台阶,一次只能上1步或2步,共多少种走法

规律:f(n) = f(n-2) + f(n-1)
......
f(3) = 3 = f(2) + f(1) (【1 1 1】、【1 2】、【2 1】)
f(2) = 2 (【1 1】、【2】)
f(1) = 1 (【1】)
*/
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 递归
* @param n 步数
* @return int
*/
public int step1(int n) {
if (n == 1 || n == 2) {
return n;
}

return step1(n-1) + step1(n-2);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 循环迭代
* @param n 步数
* @return int
*/
public int step2(int n) {
if (n == 1 || n == 2) {
return n;
}

// 初始化前两步步数
int one = 1;
int two = 2;
int sum = 0;

for (int i=3; i<=n; i++) {
sum = one + two;
// 重新记录前两步步数
one = two;
two = sum;
}

return sum;
}

1.6 局部变量和成员变量

  • 弄清楚变量作用域即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class VariableTest {
static int s;
int i;
int j;

{
int i = 1;
i++;
j++;
s++;
}

public void test(int j) {
j++;
i++;
s++;
}

public static void main(String[] args) {
VariableTest t1 = new VariableTest(); // t1:i=0,j=1,s=1
VariableTest t2 = new VariableTest(); // t2: i=0, j=1, s=2
t1.test(10); // t1:i=1, j=1, s=3
t1.test(20); // t1: i=2, j=1, s=4
t2.test(30); // t2: i=1, j=1, s=5

System.out.println(t1.i + " " + t1.j + " " + t1.s); // 2 1 5
System.out.println(t2.i + " " + t2.j + " " + t2.s); // 1 1 5
}
}

2 SSM

2.1 SpringBean作用域

1
2
3
4
<!-- scope属性用于指定bean的作用域 -->
<bean id="xx" class="xxx" scope="singleton">
<property name="xx" value="xxx"></property>
</bean>
  • Spring的Bean默认作用域为singleton,即单例,只会实例化一个
  • 其他的作用域:
类别 说明
singleton 在SpringIOC容器中仅存在一个Bean实例,spring启动自动创建
prototype 每次调用getBean()都会返回一个新的实例
request 每次http请求都会创建一个新Bean,仅适用于WebApplicationContext环境
session 同一个http session共享一个Bean,不同http session使用不同的Bean,仅适用于WebApplicationContext环境

2.2 事务传播属性

  • 事务传播行为:开启事务的A方法运行在另一个开启事务的B方法,事务运行的是A的,还是B的
1
2
3
4
5
6
7
8
9
@Transactional
public void A () {
// ......
}

@Transactional
public void B () {
A();
}
  • 事务传播属性通过@Transactional(propagation=Propagation.XXXX)来设置
  • 以下事务参数都添加在A方法
参数 说明
REQUIRED(默认) 使用B方法的事务
REQUIRES_NEW 使用A方法的事务
SUPPORTS
NOT_SUPPORTED
MANDATORY
NEVER A方法无法运行在有事务的B方法,报异常
NESTED

2.3 事务隔离级别

  • 事务并发引出问题
问题 说明
脏读 读取到别的事务更新但未提交的数据
不可重复读 事务A读取数据后,事务B修改并提交数据,事务A重新读取数据发现不一致
幻读 事务A读取表的数据,事务B向表插入新行,事务A重新读取表行数变多了
  • 隔离级别
  • 可通过@Transactional(isolation=Isolation.XXXXX)来设置方法的隔离级别
参数 说明
READ_UNCOMMITTED (读未提交) 允许读取修改但未提交的数据
READ_COMMITTED (读已提交) 只能读取已提交数据(避免脏读)
REPEATABLE_READ (可重复读) 对某字段进行操作时,其他事务无法操作此字段 (避免不可重复读)
SERIALIZABLE (串行化) 对某个表进行操作时,其他事务无法操作此表数据(避免幻读)

2.4 POST/GET请求中文乱码

  • POST:配置过滤器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!-- 参数初始化 -->
    <init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
    </init-param>
    </filter>

    <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  • GET:修改tomcat的server.xml文件(tomcat8及以上版本不用配置)

2.5 SpringMVC工作流程


2.6 Mybatis驼峰命名

  • (1)sql语句起别名
    1
    2
    3
    4
    select
    last_name lastName
    from
    table
  • (2)配置开启驼峰命名
    1
    2
    3
    <settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
  • (3)创建resultMap自定义映射
    1
    2
    3
    4
    <resultMap id="MyEmp" type="Dao.Employee">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    </resultMap>

3 Java高级

3.1 linux服务类指令


3.2 git分支命令与应用

  • 命令

3.3 redis持久化


3.4 mysql索引

  • 适合建立索引情况
  • (1)主键自动建立唯一索引
  • (2)频繁查询字段应建立索引
  • (3)外键建立索引