尚硅谷经典Java面试题一二三季

一、尚硅谷模块

1.1、第一季大佬总结

经典Java面试题(第1季)
第一季总结

1.1.2、我的一些补充

1.1.2.1、 单例设计模式

饿汉式

/**
 * @Author ljm
 * @Date 2021/10/19 21:43
 * @Version 1.0
 * 饿汉式:
 * 直接创建实例对象,不管你是否需要这个对象都会创建
 *
 * (1)构造器私有化
 * (2)自行创建,并用静态变量保存
 * (3)向外提供这个实例
 * (4)强调这是一个单例,我们可以用final修改
 */

public class Singleton1 {
    // final 一旦赋值这个变量就不能再修改
    //static 用法 https://blog.csdn.net/LIAO_7053/article/details/81408139?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
    //static final全局常量
    public static final Singleton1 INSTANCE = new Singleton1();
    public Singleton1() {
    }
}

测试

import com.atguigu.single.Singleton1;

/**
 * @Author ljm
 * @Date 2021/10/19 22:09
 * @Version 1.0
 */
public class TestSingleton1 {
    public static void main(String[] args) {
        Singleton1 s = Singleton1.INSTANCE;
    }

}

枚举类型

/**
 * @Author ljm
 * @Date 2021/10/19 22:04
 * @Version 1.0
 * 枚举类型:表示该类型的对象是有限的几个
 * 我们可以限定为一个,就成了单例
 */

/**
 * Java 枚举(enum)
 * Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
 *
 * Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。
 */
public enum Singleton2 {
    INSTANCE;
}

测试


import com.atguigu.single.Singleton2;

/**
 * @Author ljm
 * @Date 2021/10/19 22:09
 * @Version 1.0
 */
public class TestSingleton2 {
    public static void main(String[] args) {
        Singleton2 s = Singleton2.INSTANCE;
        System.out.println(s);
    }

}

静态代码块饿汉式(适合复杂实例化)

package com.atguigu.single;

import java.io.IOException;
import java.util.Properties;

/**
 * @Author ljm
 * @Date 2021/10/19 21:43
 * @Version 1.0
 *
 */

public class Singleton3 {

    //第一种方法在这个地方直接new
//    public static final Singleton3 INSTANCE = new Singleton3();
    //第二种方法
    //static 用法 https://blog.csdn.net/LIAO_7053/article/details/81408139?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

    public static final  Singleton3 INSTANCE;
    private String info;
    static {
        Properties pro = new Properties();
        try {
            pro.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
            INSTANCE = new Singleton3(pro.getProperty("info"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
    public Singleton3(String info) {
        this.info = info;
    }

    public static Singleton3 getINSTANCE() {
        return INSTANCE;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Singleton3{" +
                "info='" + info + '\'' +
                '}';
    }
}

测试



import com.atguigu.single.Singleton3;

/**
 * @Author ljm
 * @Date 2021/10/19 22:09
 * @Version 1.0
 */
public class TestSingleton3 {
    public static void main(String[] args) {
        Singleton3 s = Singleton3.INSTANCE;
        System.out.println(s);
    }

}

src/main/resources/single.properties

info=atguigu

懒汉式:延迟创建对象
线程不安全(适用于单线程)

package com.atguigu.single;

/**
 * @Author ljm
 * @Date 2021/10/19 22:04
 * @Version 1.0
 * 懒汉式:
 * 延迟创建这个实例对象
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实例
 * (3)要提供一个静态方法来获取这个实例对象
 */


public class Singleton4 {
    private static Singleton4 instance;
    private Singleton4() {

    }
    public static Singleton4 getInstance() {
        if (instance == null) {
//            try {
//                Thread.sleep(200);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            instance = new Singleton4();
        }
        return instance;
    }
}

测试
修改懒汉式代码

package com.atguigu.single;

/**
 * @Author ljm
 * @Date 2021/10/19 22:04
 * @Version 1.0
 * 懒汉式:
 * 延迟创建这个实例对象
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实例
 * (3)要提供一个静态方法来获取这个实例对象
 */


public class Singleton4 {
    private static Singleton4 instance;
    private Singleton4() {

    }
    public static Singleton4 getInstance() {
        if (instance == null) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new Singleton4();
        }
        return instance;
    }
}

import com.atguigu.single.Singleton4;

import java.util.concurrent.*;

/**
 * @Author ljm
 * @Date 2021/10/20 9:26
 * @Version 1.0
 */
public class TestSingleton4 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        Singleton4 s1 = Singleton4.getInstance();
//        Singleton4 s12 = Singleton4.getInstance();
//        System.out.println(s1 == s12);
//        System.out.println(s1);
//        System.out.println(s12);

        //Callable用法
        //https://ghsau.blog.csdn.net/article/details/7451464?spm=1001.2101.3001.6650.13&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link
        // call 方法可以有返回值,run方法没有
        Callable<Singleton4> c = new Callable<Singleton4>() {
            public Singleton4 call() throws Exception {
                return Singleton4.getInstance();
            }
        };

        //创建两个线程的线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Future<Singleton4> f1 = executor.submit(c);
        Future<Singleton4> f2 = executor.submit(c);

        Singleton4 s1 = f1.get();
        Singleton4 s2 = f2.get();

        //是有概率问题的一会true一会false
        System.out.println(s1 == s2);
        System.out.println(s1);
        System.out.println(s2);

        executor.shutdown();




    }
}

不同线程遇到延迟会产生阻塞,这样会从造成一会true一会false的情况,不同线程遇到休眠会产生阻塞,可能会出现线程由于时间不同造成创建两个不同对象的情况。

线程安全适用于多线程

package com.atguigu.single;

/**
 * @Author ljm
 * @Date 2021/10/19 22:04
 * @Version 1.0
 * 懒汉式:
 * 延迟创建这个实例对象
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实例
 * (3)要提供一个静态方法来获取这个实例对象
 */


public class Singleton5 {
    private static Singleton5 instance;
    private Singleton5() {

    }
    public static Singleton5 getInstance() {
        //https://blog.csdn.net/luoweifu/article/details/46613015  synchronized用法
        //安全问题已经解决但是我需要解决效率问题加个null判断
        if(instance == null) {
            synchronized(Singleton5.class){
                if (instance == null) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new Singleton5();
                }
            }

        }


        return instance;
    }
}

测试

import com.atguigu.single.Singleton4;
import com.atguigu.single.Singleton5;

import java.util.concurrent.*;

/**
 * @Author ljm
 * @Date 2021/10/20 9:26
 * @Version 1.0
 */
public class TestSingleton5 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        Singleton4 s1 = Singleton4.getInstance();
//        Singleton4 s12 = Singleton4.getInstance();
//        System.out.println(s1 == s12);
//        System.out.println(s1);
//        System.out.println(s12);

        //Callable用法
        //https://ghsau.blog.csdn.net/article/details/7451464?spm=1001.2101.3001.6650.13&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link
        // call 方法可以有返回值,run方法没有
        Callable<Singleton5> c = new Callable<Singleton5>() {
            public Singleton5 call() throws Exception {
                return Singleton5.getInstance();
            }
        };

        //创建两个线程的线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Future<Singleton5> f1 = executor.submit(c);
        Future<Singleton5> f2 = executor.submit(c);

        Singleton5 s1 = f1.get();
        Singleton5 s2 = f2.get();

        //是有概率问题的一会true一会false
        System.out.println(s1 == s2);
        System.out.println(s1);
        System.out.println(s2);

        executor.shutdown();




    }
}

无论如何修改延迟时间我们发现都是true

静态内部类形式(适用于多线程)

package com.atguigu.single;

/**
 * @Author ljm
 * @Date 2021/10/20 10:10
 * @Version 1.0
 * 在内部类被加载和初始化时,才创建INSTANCE
 * 静态类不会随着外部类的加载和初始化而初始化,它是要单独加载和初始化的
 * 因为在内部类加载和初始化时创建的因此是线程安全的
 */
public class Singleton6 {

    private Singleton6(){

    }
    private static class Inner{
        private static final  Singleton6 INSTANCE = new Singleton6();
    }
    public static Singleton6 getInstance() {
        return Inner.INSTANCE;
    }
}

1.1.1.2、基本数据类型和引用类型

对应尚硅谷第一季的4、方法参数传递机制章节

Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。

引用类型包括三种:
类 Class
接口 Interface
数组 Array
方法的参数传递机制

1、形参是基本数据类型

传递数据值

2、实参是引用数据类型​

传递地址值

​ 特殊的类型:String、包装类等对象的不可变性

1.2.3、 5、递归与迭代

首先看一道编程题如下:
有 n 步台阶,一次只能上 1 步或者 2 步,共有多少种走法?

1、递归fen

分析如图,当n等于1或者2时,走法就等于n,从第三层台阶开始,每一层台阶为前两层台阶走法之和。

在这里插入图片描述

2、迭代

用 one、two 这两个变量来存储 n 的最后走一步和最后走两步,从第三层开始走,用 sum 来保存前两次的走法的次数,sum = two + one; 然后 two 移到 one,one 移到 sum 循环迭代。

在这里插入图片描述

代码如下:

/**
 * 编程题:有 n 步台阶,一次只能上 1 步或者 2 步,共有多少种走法
 */
public class Code_05_StepProblem {

    @Test
    public void test() {
        // 时间复杂度 ...
//        long start = System.currentTimeMillis();
//        System.out.println(recursion(40)); // 165580141
//        long end = System.currentTimeMillis(); // 537
//        System.out.println(end - start);

        // 时间复杂度 O(n)
        long start = System.currentTimeMillis();
        System.out.println(iteration(40)); // 165580141
        long end = System.currentTimeMillis(); // 0
        System.out.println(end - start);
    }

    // 递归实现
    public int recursion(int n) {
      if(n < 1) {
          return 0;
      }
      if(n == 1 || n == 2) {
          return n;
      }
      return recursion(n - 2) + recursion( n - 1);
    }

    // 迭代实现
    public int iteration(int n) {
        if(n < 1) {
            return 0;
        }
        if(n == 1 || n == 2) {
            return n;
        }
        int two = 1; // 一层台阶,有 1 走法, n 的前两层台阶的走法
        int one = 2; // 二层台阶,有 2 走法, n 的前一层台阶的走法
        int sum = 0; // 记录一共有多少中走法
        for(int i = 3; i <= n; i++) {
                sum = two + one;
                two = one;
                one = sum;
        }
        return sum;
    }
}

总结:

1)方法调用自身称为递归,利用变量的原值推出新值称为迭代。

2)递归

优点:大问题转为小问题,可以减少代码量,同时代码精简,可读性好;

缺点:递归调用浪费了空间,而且递归太深容易造成堆栈的溢出。

3)迭代

优点:代码运行效率好,因为时间复杂度为0(n),而且没有额外空间的开销;

1.2.4、Spring Bean 的作用域之间有什么区别?

默认情况下,Spring只为每个在I0C容器里声明的bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例。该作用域被称为singleton,它是所有bean的默认作用域。
在Spring的配置文件中,给bean加上scope属性来指定bean的作用域如下:

singleton:唯一 bean 实例,Spring 中的 bean 默认都是单例的。

prototype:每次请求调用getBean()都会创建一个新的 bean 实例。

request: 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前WebApplicationContext内有效。

session:每一次 HTTP 请求都会产生一个新的 bean,不同的HTTP session 使用不用的bean,该 bean 仅在当前WebApplicationContext内有效。

global-session:全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

1.2.5、mysql主键外键

mysql主键外键

第二季

2.1、大佬总结

第二季大佬总结
另一个大佬总结
另一个大佬github版本

2.2、我的一些补充

并发:多个线程非同时但一块执行;并行:多个线程同时一块执行;

StackoverFlowError

堆栈溢出,我们有最简单的一个递归调用,就会造成堆栈溢出,也就是深度的方法调用

栈一般是512K,不断的深度调用,直到栈被撑破

OutOfMemoryError java heap space

创建了很多对象,导致堆空间不够存储

OOM之Metaspace

永久代(Java8后被原空向Metaspace取代了)存放了以下信息:

虚拟机加载的类信息
常量池
静态变量
即时编译后的代码

注意:这里的常量池是指的运行时常量池,并非string table(字符串常量池)
这里有点问题,字符串常量池和静态变量在1.7及其之后就放入了堆中,参考宋红康老师的

STW

停顿时间

第三季

3.1、大佬总结

大佬总结

3.2、我的一些补充

二、其他大佬总结

Spring常见面试题总结(超详细回答)

15个经典的Spring面试常见问题

MyBatis+Spring+SpringMVC框架面试题整理(一)

JAVA关于Spring 面试题汇总

Spring的几个经典常见面试题

  • 3
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值