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