初始化
构造器
默认构造器
- 当在类中没有写构造器的时候,编译器会认为你忘记了这件事情,默认为你加上一个无参的构造器。
- 当自己写了构造器后,编译器认为你知道自己想要什么,于是认为你不需要编译器的帮助,因此,需要自己选择写或不写无参构造器
使用this和super
- this可以帮助调用同一个类的其他构造器
- super可以调用父类的构造器
- 它们必须是第一条语句
- this与super不可兼得,因为他们必须是第一条语句
- 但是可以曲线救国
使用初始化块
1 | //该静态块会在构造方法执行前执行 |
关键字
this
- 只在必要的地方使用this,可以便于阅读
- this在方法中表示操作该方法的对象,并且方法可以返回一个this
return this
- 可以实现一种x.getthis().getthis().print();
- 即多次递归调用
super
static
它是静态的,意味着不能加载动态资源,即不能加载对象的属性以及非静态的资源
静态资源的初始化
- 当没有赋初值,静态资源会获得基本类型的标准初值,例如int为0,引用为null
- 创建时间:在创建第一个table对象,或第一次加载类,或第一次访问静态资源
- 初始化顺序:
- 先静态对象,即类中的static的资源
- 后非静态对象。
显式的静态初始化
使用静态块,将所有的静态语句组织起来
static {
i=47;
h=50;
}
数组初始化
初始
int[] a或 int a[]
- 为什么不能确定大小?
- 因为初始化的只是对对象的一个引用,并没有分配内存空间,只是表明这是一个数组对象,引用哪来的大小
初始化的方法
int[] a= new int(5);//方法1
Integer[] a ={ //方法2
new Integer(1),
new Integer(2),
};
Integer[] b=new Integer[]{ //方法3
new Integer(1),
new Integer(2),
};
可变参数列表
实现
public void printArr(Object ... args){
for (Object obj : args)
System.out.println(obj + " ");
}
终结条件
- finalize对象终结条件的验证if()
- System.gc()强制执行终结动作
清理
牢记
- 垃圾回收只与内存有关
- 对象可能不会被垃圾回收
- 垃圾回收不等于”析构”(C++)
垃圾回收器的工作范围
- 垃圾回收器只会回收通过new分配的内存
- 垃圾回收只与内存有关
- 对象可能不会被垃圾回收
- 垃圾回收或者终结,不一定发生,如果JVM未面临内存耗尽,不会浪费时间去执行垃圾回收以恢复内存
特殊情况
- 获得一块非new的特殊内存
- 例如对象将自己绘制到了屏幕上,需要在对象销毁时候,将自己擦除
- 由于不是new得到的内存,因此垃圾回收器无法处理
解决方案:定义finalize()方法
- finalize必须与内存相关,因为垃圾回收器只与内存有关
- 垃圾回收期准备释放对象的内存
- 调用finalize方法
- 在下一次垃圾回收动作发生时,真正回收对象占用的内存
垃圾回收器的工作方式
引用计数法
- 当有引用连接至对象时,引用计数+1
- 当引用离开作用域或者被置为null,引用计数-1
- 缺陷
- 如果对象间存在循环引用,可能出现对象应该被回收,但引用计数不为0
- 工作量极大,速度极慢
对任何活的对象,一定能最终追溯到其存活的堆栈或静态存储区之中的引用
- 实现方法
- 停止-复制法
- 暂停程序运行,将所有的活对象复制到一个新的堆内,没有被复制的都是垃圾,在新堆上,对象紧密排列
- 效率低,内存开销大
- 当只有少量的垃圾,较为浪费
- 标记清扫法
- 每找到一个活的对象,进行标记,没有被标记的被清扫
- 自适应
- JVM监视,如果所有对象很稳定,采用标记清扫,如果出现很多碎片,采用停止复制
- 分代
- 内存分配以块为单位
- 大型对象会单独占用一个块
- 每个块有相应代数记录是否存活
- 垃圾回收器对上次回收动作后新分配的块进行整理,对处理大量短命的对象很有效果
- 定期进行清扫,大型对象不会被清扫(代数增加),内涵小型对象的块会被复制整理
- 即时编译器JIT
- 将程序全部或者部分翻译成机器码
- 当装载某个类
- 寻找.class文件,将该文件字节码装入内存
- ###有两种方案
- JIT编译全部代码
- 缺陷
- 加载动作散落在整个程序生命周期
- 增加可执行代码的长度,降低速度
- ###方案二
- 惰性评估
- JIT只在必要的时候编译代码
###成员初始化
#构造器与垃圾收集器
内存区域
- 堆:对象的生存空间 实例变量–声明在类里面而不是方法里
- 栈:方法调用和变量的生存的空间 局部变量
- 在方法里使用Duck d=new Duck();d在栈里,因为他是对象的引用,d所引用的对象在堆里面
方法进入栈的方式
调用一个方法,方法会被放在调用栈的栈顶,
如果该方法要调用另一个方法,则该另一个方法会放在原方法的上面
放在栈上的方法是一个堆栈块,带有方法的状态\执行到哪一段程序及所有的局部变量
对象生命周期
- 当对象的引用全部消失,以及无法取得对象的引用,那么符合垃圾回收器的条件
- 对象引用可以是Null,但是对null操作是运行时异常,所有编译器没有问题