尚硅谷面試題——第一季(一)

自增

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 的工作流程

在這裏插入圖片描述
在這裏插入圖片描述

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