JAVA面试题整理

尚硅谷JAVA面试 第一季

1.自增变量

代码

public class Test{
public static void main(String[] args){
	int i =1;  
	i=i++;  
	int j = i++; 
	int k = i+ ++i * i++;
	System.out.println("i ="+ i); // 4
	System.out.println("j"+ j); // 1
	System.out.println("k"+ k); //11 
	}
}

2.单例模式

2.1 什么是singleton

  • singleton:在Java中即指单例模式,他是软件开发中最常用的设计模式之一。
  • 单:唯一
  • 例:实例
  • 单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。
  • 例如:代表JVM运行环境的Runtime类

2.2 要点

  • 一是某个类只能有一个实例
    ⬛ 构造器必须私有化
  • 二是它必须自行创建这个实例
    ⬛ 含有一个该类的静态变量来保存这个唯一的实例
  • 三是它必须自行向整个系统提供这个实例
    ⬛ 对外提供获取该实例对象的方式:
    (1) 直接暴露 (2)用静态变量的get方法获取

2.3 几种常见的形式

  • 饿汉式:直接创建对象
    • 直接实例化(简洁直观)
/**
 * 饿汉式:
 *  直接创建这个对象,不管你是否需要这个对象
 *
 *  (1) 构造器私有
 *  (2) 自行创建,并且用静态变量进行保存
 *  (3) 向外提供这个实例
 *  (4) 强调这是一个单例,我们可以用final 修饰
 */
public class Singleton1 {

    public static final Singleton1 INSTANCE = new Singleton1();

    private Singleton1(){

    }
}

- 枚举式(最简洁)

public enum Singleton1 {
    INSTANCE
}
- 静态代码块饿汉式(适合复杂实例化)
import java.io.IOException;
import java.util.Properties;

public class Singleton1 {
    public static Singleton1 INSTANCE ;

    private String info;

    static {
        Properties pro = new Properties();
        try {
            pro.load(Singleton1.class.getClassLoader().getResourceAsStream("Singleton.properties"));
            INSTANCE  = new Singleton1(pro.getProperty("info"));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    private Singleton1(String info){
        this.info = info;
    }
}
  • 懒汉式:延迟创建对象
public class Singleton1 {
    private Singleton1() {}
    private static Singleton1 instance;
    public static Singleton1 getInstance() {
        if (instance == null) {
        //为了演示线程安全问题 可以睡眠 
        //Thread.sleep();
            instance = new Singleton1();
        }
        return instance;
    }
}
- 线程安全(适用于多线程)
public class Singleton1 {
    private Singleton1() {
    }

    private static Singleton1 instance;

    public static Singleton1 getInstance() {
        synchronized (Singleton1.class) { //加锁
            if (instance == null) {
                instance = new Singleton1();
            }
            return instance;
        }

    }
}

为了性能可以优化

public class Singleton1 {
    private Singleton1() {
    }

    private static Singleton1 instance;

    public static Singleton1 getInstance() {
        if (instance == null) { //如果有就直接返回
            synchronized (Singleton1.class) {
                if (instance == null) {
                instance = new Singleton1();
            	}
            }
        }

        return instance;
    }
}
- 静态内部类形式(适用于多线程)
/**
 * 内部类并不会随着外部类的加载而加载 只有当时用的时候才会去加载
 */
public class Singleton1 {

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

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

}

3. 类加载过程

  • 类初始化过程

    (1) 一个类要创建实例需要先加载并初始化该类
      ◇ main方法所在的类需要先加载和初始化
    
    (2) 一个类初始化必须先初始化父类
    (3) 一个类初始化就是执行()方法
      ◇<clinit>()方法由静态变量显示赋值代码和静态代码块组成
      ◇ 类变量显示赋值代码和静态代码块代码从上到下顺序执行
      ◇ <clinit>()方法只执行一次
    
  • 实例初始化过程

      ◇<init>()方法可能重载多个,有几个构造器就有几个<init>方法
      ◇ <init>()方法由非静态实例变量显示赋值代码和非静态代码块、对应构造器代码组成
      ◇ 非静态实例变量显示赋值代码和非静态代码块代码从上到下顺序执行,而对应构造器的代码最后执行
      ◇ 每次创建实例对象,调用对应构造器,执行的就是对应的<init>方法
      ◇ <init>方法的首行是supper()或者super(实参列表),即对应父类的<init>方法
    
  • 方法的重写

    (1) 哪些方法不能被重写
      ◇ final方法	
      ◇ 静态方法
      ◇ private 等子类中不可见方法
    
    (2) 对象的多态性
      ◇  子类如果重写了父类的方法,通过子类对象调用的一定是子类重写的代码
      ◇ 非静态代码默认的调用对象是this
      ◇ this对象在构造器或者说<init>方法中就是正在创建的对象
    

4. 例子

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;
    }
}
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");
    }

    public int test(){
        System.out.print("  9");
        return 1;
    }
    public static int method(){
        System.out.print("  10");
        return 1;
    }

    public static void main(String[] args) {
        Son son = new Son();
        System.out.println();
        Son son1 = new Son();


    }


}

结果 :
5 1 10 6 9 3 2 9 8 7
9 3 2 9 8 7

5.方法的传参机制

(1) 参数是基本类型

	传递数据值

(2) 参数是引用数据类型

	传递地址值
	特殊的类型:String、包装类等对象不可变性
### 例子
public class Exam4 {

    public static void main(String[] args) {

        int i = 1;

        String str = "hello";


        Integer num = 20;

        int[] arr ={1,2,3,4};
        change(i,str,num,arr);

        System.out.println("i"+ i);
        System.out.println("str"+ str);
        System.out.println("num"+ num);
        System.out.println("arr"+ Arrays.toString(arr));


    }

    private static void change(int i, String str, Integer num, int[] arr) {

        i +=1;

        str+= "word";

        num +=1 ;

        arr[0] += 1;
    }

}
//结果 
/*
i 1
str hello
num 20
arr [2, 2, 3, 4]
*/

6. 递归与迭代 (斐波那契数列)

import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestRabbit {


    /**
     * 假如一对兔子每月能生一对小兔,而每对小兔在出生后的第三月开始生一对兔子。
     * 假如在不发生死亡的情况下,由一对出生的兔子开始,一年后会有多少只兔子?
     */


    public static void main(String[] args) {
        Instant start = Instant.now();
        /*   测试 50  */
        System.out.println(getRabbitNum(50)); // 20365011074  20436MS
        System.out.println(getRabbitNumByLoop(50));  // 20365011074 0MS
        System.out.println(getRabbitNumByLamdba(50)); // 20365011074 47MS
        Instant end = Instant.now();
        System.out.println(Duration.between(start, end).toMillis()); 
    }

    public static long getRabbitNumByLamdba(int num) {
        List<Long> collect = Stream.iterate(new long[]{0L, 1L}, nums ->
                        new long[]{nums[1], nums[0] + nums[1]})
                .limit(num + 2) //如果要和上面的作比较  需要加 2
                .map(nums -> nums[0]).collect(Collectors.toList());
        return collect.get(collect.size() - 1);


    }


    //使用迭代
    // 1  1  2  3  5  8  13
    public static long getRabbitNumByLoop(int num) {
        if (num <= 2 && num > 0) {
            return num;
        }
        long one = 2;
        long two = 1;
        long sum = 0;
        for (int i = 3; i <= num; i++) {
            sum = one + two;  //加上之前月的
            two = one; //将当前月份的前一个月重新赋值
            one = sum;//设置当前月份的值
        }
        return sum;
    }


    //使用递归
    public static long getRabbitNum(int num) {
        if (num <= 2 && num > 0) {
            return num;
        }
        return getRabbitNum(num - 2) + getRabbitNum(num - 1);
    }


}

7. 成员变量与局部变量

public class Exam5 {
    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) {
        Exam5 obj1 = new Exam5(); // j = 1  s = 1 i =0 
        Exam5 obj2 = new Exam5(); // j = 0 s= 2 i =0
        obj1.test(10); // j = 1  s = 3 i =1 
        obj1.test(20);// j = 1  s = 4 i =2 
        obj2.test(30); // j = 1  s = 5 i =1 
        System.out.println(obj1.i + "," + obj1.j + "," + obj1.s); // 2 2 5
        System.out.println(obj2.i + "," + obj2.j + "," + obj2.s); // 1 1  5

    }
}

8 Spring Bean 的作用域

	可以通过scope属性来指定bean的作用域
	singleton:默认值。当IOC容器一创建就会创建bean的实例,而且是单例,每次得到的都是同一个
	prototype:原型。当IOC容器一创建不在实例该bean,每次调用getBean方法再实例该bean,每次的对象不一样
	request:每次请求实例化一个bean
	session:在一次回话中共享一个bean

8 Spring 传播行为和隔离级别

	1.propagation:用来设置事务的传播行为
			事务的传播行为:一个方法运行在一个开始了事务的方法中时当前方法是使用原来的事务还是开启一个新的事务
			Propagation.REQUIRED : 默认值 使用原来的数据
			Propagation.REQUIRES_NEW :将原来的数据挂起,开启一个新的任务
	2..isolation:用来设置事务的隔离级别
			Isolation.REPEATABLE_READ:可重复读,MYSQL默认级别
			isolation.READ_COMMITTED:读已提交,Oracle默认级别
传播属性描述
REQUIRED如果有事务在运行,当前的方法就在这个事务运行,否则就开启一个新的事务,并在自己的事务中运行
REQUIRES_NEW当前的方法必须启动新事物,并在它自己的事务中运行,如果有事务在运行,应该将它挂起
SUPPORTS如果有事务在运行,当前的方法就在这个事务运行,否则就不运行在事务中
NOT_SUPPORTED当前方法不应该运行在事务中,如果有事务,将它挂起
MANDATORY当前方法必须运行在事务中,如果没有事务将会抛出异常
NEVER当前方法不应该运行在事务中,如果有事务将会抛出异常
NESTED如果有事务运行,当前的方法就应该在这个事务中嵌套事务运行,否则就启动一个新的事务,并在自己的事务中运行

8.1 数据库事务并发问题

1.脏读
	1. T1 将某条记录的AGE值从 20 改为 30
	2. T2 读取 T1 更新后的值 30
	3. T1 回滚,AGE的值又成为 20 
	4.  T2 读取到 的 30 就是一个无效值
2. 不可重复读
	1. T1 读取 AGE 的值 为20
	2. T2 将AGE 的值修改为 30
	3. T1再次读取AGE值为30 和第一次读取不一致
3. 幻读
	1. T1 读取 Student 表中的一部分数据
	2. T2 向student 中插入一条数据
	3. T1 再次读取,会读取到新的行 

8.2 隔离级别

1. 读未提交
2. 读已提交
3. 可重复读 (mysql 默认)
4. 串行化
隔离级别脏读不可重复读幻读
READ UNCOMMITED
READ COMMITED
REPEATABLE READ
SERVIALIZABLE

9 Spring MVC 运行流程

在这里插入图片描述

10 mybatis 字段名和属性名不一致解决方法

	1. 使用别名
	2. 使用resultMap
	3. 驼峰命名

11 Linux常用的命令(感觉面试不会问我,就不整理了)

Service (centos6)

	service 服务名 start
	service 服务名 stop
	service 服务名 restart
	service 服务名 reload
	service 服务名 status
	**查看服务的方法**  /etc/init.d/服务名
	通过chkconfig命令设置自启动
	查看服务 chkconfig --list | grep XXX
	chkconfig --level 5 服务名 on

	jar -xvf xxx.jar  解压jar
	ps -ef | grep tomcat  查看Tomcat
	kill -9   强制杀死进程
	tail -f ca...out  tomcat日志

11 git 命令

创建分支

	git branch <分支名>
	git branch -v 查看分支

切换分支

	git checkout <分支名>
	一步完成 git checkout -b <分支名>	

合并分支

	先切换到主干  git checkout master
	git merge <分支名>

删除分支

	先切换到主干 git checkout master
	git branch -D <分支名>

12 Redis

RDB

	在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是快照,他恢复时是将快照文件直接读到内存里

备份是如何执行的

	Redis会单独创建一个子进程来持久化,会将数据写入到临时文件中,待持久过程都结束了,再用这个临时文件替换上次持久
	好的文件。整个过程中,主进程是不进行任何IO操作,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对数据恢
	复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效,RDB的缺点是最后一次持久化后的数据可能丢失

RDB的优点

  • 节省磁盘空间
  • 恢复速度块

RBD的缺点

  • 数据大时耗性能
  • 每隔一段时间进行备份,上次备份之后下次备份之前,Redis挂了,此时数据并没有写入文件中

AOF

	以日志的形式来记录每个写操作,记录的是REDIS执行的命令,Redis启动之初会读取该文件重新构建数据,换言之,
	就是读取文件中的命令,执行一遍

何时重写

	重写虽然可以节约大量磁盘空间,减少恢复时间,但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件
	才会进行重写
	auto-aof-rewrite-percentage 100
	auto-aof-rewrite-min-size 64mb
	系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设置为base_size,如果Redis的AOF 当前大小>=base_size 
	+ base_size * 100%(默认)且当前大小 >= 64MB (默认)的情况下,会对AOF重写

AOF的优点

  • 备份机制更稳健,丢失数据概率低
  • 可读的日志文本,通过操作AOF文件,可以防止误操作

AOF的缺点

  • 占磁盘空间
  • 恢复备份速度慢
  • 每次读写同步的话,有一定的性能压力
  • 存在个别bug,造成恢复不能

13 Mysql 那种情况适合建立索引

	参考 https://blog.csdn.net/qq_45757978/article/details/122951105?spm=1001.2014.3001.5502

TODO 剩余的以后用到了再整理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值