尚硅谷面试题——第一季(一)

自增

public class Increment {
    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
    }
}

反编译为字节码:

 public static void main(java.lang.String[]);
    Code:
    	//int i = 1;
       0: iconst_1		//将1压入栈顶
       1: istore_1		//将int类型值存储局部变量1(1赋值给i)
       2: iload_1		//后置++,所以先将i的值存储起来,压入栈顶
       3: iinc          1, 1  //自增,将局部变量1的值+1,此时i的值为2 		
       6: istore_1		//赋值,将栈顶的1赋值给局部变量1,即i,此时i的值被覆盖,变成1
       //int j = i++;
       7: iload_1		//后置++,所以先将i的值存储起来,压入栈顶
       8: iinc          1, 1  //自增,将局部变量1的值+1,此时i的值为2 
      11: istore_2		//赋值,将栈顶的1赋值给局部变量2,即j,j的值变为1
      //int k = i + ++i * i++;
      12: iload_1	//将局部变量1的值压入栈顶,即i的值,为2;
      13: iinc          1, 1	//前置++,直接将局部变量1的值+1,即i的值变为3
      16: iload_1	//将局部变量1的值压入栈顶,即3
      17: iload_1	//后置++,所以先存储值,将局部变量1的值压入栈顶,即i的值3压入栈顶
      18: iinc          1, 1 //自增,将局部变量1的值+1,此时i为4
      //此时栈: 栈顶 -->  3 -->  3  --> 2
      21: imul   //imul,弹出两个值计算:3 * 3 = 9,9再压入栈顶
      22: iadd	 //iadd,弹出两个值计算:9 + 2 = 11,11再压入栈顶
      23: istore_3 	//赋值,将栈顶的11赋值给局部变量3,即k
      //后面为io操作,省略...
      24: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      27: new           #3                  // class java/lang/StringBuilder
      30: dup
      31: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      34: ldc           #5                  // String i=
      36: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      .....

类初始化与实力初始化

public class Father {
    private int i = test();
    private static int j = method();

    static {
        System.out.println("(1)");
    }
    Father() {
        System.out.println("(2)");
    }
    {
        System.out.println("(3)");
    }
    public int test() {
        System.out.println("(4)");
        return 1;
    }
    private static int method() {
        System.out.println("(5)");
        return 1;
    }
}

public class Son extends Father {
    private int i = test();
    private static int j = method();
    static {
        System.out.println("(6)");
    }
    Son() {
        System.out.println("(7)");
    }
    {
        System.out.println("(8)");
    }
    public int test() {
        System.out.println("(9)");
        return 1;
    }
    public static int method() {
        System.out.println("(10)");
        return 1;
    }

    public static void main(String[] args) {
        Son s1 = new Son();//5,1,10,6,9,3,2,9,8,7
        System.out.println();
        Son s2 = new Son();//9,3,2,9,8,7
    }
}

类初始化:

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

实例初始化过程:

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

方法重写Override:

非静态方法前面其实一直有一个默认的隐式参数this
this在构造器(或<init>)它表示的是正在创建的对象,普通方法中表示当前对象。

所以Father中的test()方法在被调用时,this是子类的,所以执行的是子类的test()方法,即重写。

  • 哪些方法不可以被重写

    • final方法
    • 静态方法
    • private等子类中不可见的方法
  • 对象的多态性

    • 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
    • 非静态方法默认的调用对象是this
    • this对象在构造器或者说<init>方法中就是正在创建的对象

方法的参数传递机制

public class Exam4 {
    public static void main(String[] args) {
        int i = 1;
        String str = "hello";//在常量池
        Integer num = 200;//-128 ~ 127在常量池
        int[] arr = {1, 2, 3, 4, 5};
        MyData my = new MyData();

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

        System.out.println("i = " + i);//1
        System.out.println("str = " + str);//hello
        System.out.println("num = " + num);//200
        System.out.println("arr = " + Arrays.toString(arr));//2,2,3,4,5
        System.out.println("my.a = " + my.a);//11

    }

    public static void change(int j, String s, Integer n, int[] a, MyData m) {
        j += 1;
        s += "world";
        n += 1;
        a[0] +=1;
        m.a += 1;
    }
}

class MyData {
    int a = 10;
}
  • 形参是基本类型时:传数据值
  • 实参是引用数据类型:传递地址值
  • 特殊:String、包装类对象不可变

递归和迭代

问题:有n步台阶,一次只能上1步或2步,共有多少种走法?

public class DiGui {


    public static void main(String[] args) {
        int length = 20;
        System.out.println(recursion(20));
        System.out.println(circle(20));
    }

    /**
     * 递归:
     * f(1) = 1
     * f(2) = 2
     * f(3) = f(1) + f(2)
     * f(n) = f(n - 1) + f(n - 1)
     */
    public static int recursion(int n) {
        if ( n == 1 || n == 2) {
            return n;
        }
        return recursion(n - 2) + recursion(n - 1);
    }


    public static int circle(int n) {
        int[] arr = new int[3];
        arr[0] = 1;
        arr[1] = 2;
        if (n == 1)
            return arr[0];
        if (n == 2)
            return arr[1];
        for (int i = 3; i <= n; i++) {
            arr[2] = arr[0] + arr[1];
            arr[0] = arr[1];
            arr[1] = arr[2];
        }
        return arr[2];
    }
}

成员变量与局部变量

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

    }
}

Spring中Bean作用域的区别

在Spring中,可以在<bean>元素的scope属性里设置bean的作用域。

默认情况下,Spring只为每个在IOC容器里声明的bean创建唯一一个实例,整个IOC容器范围都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例,该作用域被称为singleton,它是所有bean的默认作用域。

类别 说明
singleton 在Spring IOC容器中仅存在一个Bean实例,Bean一旦实例的方式存在
prototype 每次调用getBean()时都会返回一个新的实例
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTPSession共享一个Bean,不同的HTTP Session使用不同的Bean。该作用域仅适用于WebApplicationContext环境
globalSession 同一个全局 Session 共享一个 bean, 用于 Porlet, 仅用于 WebApplication 环境。

Spring支持的常用数据库事务传播属性

在这里插入图片描述

默认情况为:PROPAGATION_REQUIRED,可以通过@Transactional(propagation = Propagation.XXXX)来设置。

Oracle和MySQL对隔离级别的支持:

Oracle MySQL
READ UNCOMMITTED
READ CMMITTED ✅(默认)
REPEATABLE READ ✅(默认)
SERIALIZABLE

Spring MVC解决Post请求乱码

<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>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Spring MVC 的工作流程

在这里插入图片描述
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章