自增
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
}
}
類初始化:
- 一個類要創建實例需要先加載並初始化該類
- main方法所在的類要先加載和初始化
- 一個子類要初始化需要先初始化父類
- 一個類初始化就是執行
<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 的工作流程