文章目录
- 自增变量
- 单例设计模式
- 饿汉-直接实例化饿汉式
- 饿汉-枚举式
- 饿汉-静态代码块
- 懒汉式-线程不安全
- 懒汉式-线程安全
- 懒汉式-静态内部类
- 类初始化和实例初始化
- 类初始化的过程
- 实例初始化的过程
- 方法重写
- 方法的参数传递机制
- 方法的传参机制
- String、包装类等对象的不可变性
- 递归与迭代
- 递归
- 循环递归
- 总结
- 成员变量与局部变量
- 知识点
- 解析
- 局部变量与成员变量的区别
- jvm内存(扩展)
- 重名区分
自增变量
运行的结果:
解析:
对于:i=i++
这一行运算完了之后,i的值还是1.上述这个123对应的是字节码的操作。
int j = i++,类似上面,运算完了之后j是1.但是因为i进行了++,所以这一步最终i变成了2.
int k = i + ++ii–
操作数栈就是你运算的时候还没赋值给某个变量的时候,变量值暂存的地方。局部变量空间就是最终赋值的时候,所在的空间。
也就是说,最后运算的是:int k = 2+33=11.
总结:
单例设计模式
饿汉-直接实例化饿汉式
饿汉-枚举式
jdk1.5之后出的这种形式。因为枚举来自1.5版本。
饿汉-静态代码块
效果跟直接饿汉式是一样的。但是负责度上来了。使用场景往往是有变量需要在初始化的时候赋值的时候。如:
饿汉式都是不存在线程安全问题的。在类初始化的时候,直接创建实例对象。
懒汉式-线程不安全
单线程情况下是没有问题的。多线程就出问题了。会创建多个实例。
多线程测试:
模拟创建对象的过程:
最终的结果就是创建了 多个实例了。
懒汉式-线程安全
使用同步关键字:
上面这种方式,实际上是防止创建时候并发,创建完了之后,直接返回就可以了,这样可以改造一下。
懒汉式-静态内部类
在内部类被加载和初始化时才创建对象。
静态内部类不会随着外部类的加载和初始化而初始化。他是要单独加载和初始化的。这样就实现了延迟创建对象。
因为是在内部类加载和初始化时创建的,因此是线程安全的。
这种方式最简洁,最推荐。
类初始化和实例初始化
运行结果:
类初始化的过程
所以对于上面,要初始化子类,会先初始化父类。先初始化静态变量和代码块谁在上面谁先初始化。
所以先执行父类的method方法和静态代码块,打印5,1。
然后执行子类的method静态方法和静态代码块,这里静态不存在重写,打印10,6.
实例初始化的过程
关于super这里声明一点:写或者不写,在子类构造器中一定会调用父类的构造器。
所以:
所以创建实例会打印:
父类:9-3-2
子类:9-8-7
方法重写
进阶:
方法的参数传递机制
运行结果:num 应该是2
分析:
然后调用方法,在栈上开辟一块空间存局部变量。发生了实参给形参赋值。内存的变化如下:
接下来,执行方法里面的操作。要遵循方法的传递机制。
所以i,string,integer,操作完了之后,对原来的变量没有影响。
string拼接之后,在常量池里有了新的地址,发生了重新的指向。integer也是一样的道理。
对于数组,传递的是地址,所以原来方法里面的数组也发生了变化。对于obj对象,也是传递的地址,对以前对象里面的成员变量发生了改动。
方法的传参机制
String、包装类等对象的不可变性
递归与迭代
针对这种类型的问题,有2种处理方式,递归或者迭代循环。
递归
进行分析,分析最后一步可能走一步或者两步,抽象出递归的公式。
代码实现,设计函数f(n):
循环递归
思路就是通过分析,保存前两步的值,加起来就对了,就是我们想要的值。
这种写法,不太好理解,编写起来也更复杂。但是解释度比递归要好。
总结
成员变量与局部变量
运行结果:
知识点
解析
首先非静态代码块中的i是指的非静态代码块中声明的i,这是就近原则。
参数中传进去一个j,然后全局变量也有j,此时就近原则,指的是参数中的j。
就近原则,还要遵守作用域的限制,所以15行的i指的是全局变量i,不是非静态代码块中的i。
局部变量与成员变量的区别
实例变量是有初始化值的,比如你int,初始化值为0.
jvm内存(扩展)
对于本题目,jvm三块空间的内存模型:
重名区分