第五章:初始化与清理

初始化清理是涉及安全的两个问题。

1 构造器

1.1 构造器与类同名,用来确保对象的初始化;

1.2 构造器分为默认无参构造和自定义构造(无参和有参都行),构造器支持重载,但是一旦自定义构造,系统自动放弃默认构造;

1.3 Java中对象的创建和初始化是捆绑一起的;

1.4 构造器内部可以使用this关键字调用构造器,但必须放在句首(所以只能调用一个);

2 重载

2.1 同一类中方法名相同但是参数列表不相同(包括参数顺序不同和参数不同),称为方法的重载;

2.2 如果传入的实际参数类型小于方法声明的形式参数类型,实际参数类型会被提升(向上造型)

       如果传入的实际参数类型大于方法声明的形式参数类型,实际参数类型必须通过类型转换执行窄化转换(向下造     型);

清理(自适应GC):

3.1 

       a、对象可能不被垃圾回收;

b、垃圾回收不等于析构;

c、垃圾回收只和内存有关;

d、Java虚拟机(JVM)如果并未面对内存耗尽的情况,一般不会停止程序以执行垃圾回收恢复内存;

3.2 两种模式

        和C++内存管理就像个院子,每个对象都有自己的地盘,对象销毁地盘重用。而java中堆的实现更像是传送带,每分配一个对象就往前移动一格。java的“堆指针”只是简单的移动到尚未分配的区域,比C++在堆栈上查找可用空间的开销小得多。

3.2.1 "停止-复制"模式:

思路:暂停程序运行,然后将所有存活对象复制到另一个堆里,当对象复制到新堆时,是一个挨着一个保持紧凑排列,重新修正所有引用,清理原来的堆。

弊端

1、资源消耗,需要两个堆;跨堆交互,效率低下。解决:按需从堆中分配“”,复制动作发生在这些内存块之间。

2、复制模式不能一直使用。程序稳定运行后,产生的碎片垃圾很少,此时依然采用复制模式对资源的效果就格外严重,所以需要“标记-清扫”模式。

3.2.2 "标记-清扫"模式:

思路:从静态区和栈出发,遍历所有引用,找到所有存活对象。每找到一个存活对象,给该对象一个标记。全部标记完成后,清理没有被标记的对象。因为不发生任何复制工作,所以剩下的堆空间是不连续的,垃圾回收器如果想要得到连续的堆空间,需要重新整理。

3.3 "自适应的、分代的、停止-复制、标记-清理式垃圾回收器"

思路:JVM中内存分配以较大的“”为单位,垃圾回收器可以在回收期间向“废弃块”中拷贝对象。每个块都有自己的代数记录它是否还存活(这对大量临时对象的回收很有帮助),块被引用,代数增加。垃圾回收器会定期进行清理工作(大型对象/块不会被复制,代数会增加,小型对象的块会被复制并整理)。

        JVM会进行监视,当对象都很稳定时,会切换到"标记-清扫"模式。同样,如果堆空间碎片增多,会切换为"停止-复制"模式。

个人认为块的存在时以部分冗余换取时间效率。

 

4 初始化

4.1 成员初始化

4.1.1 存储

栈用来存储基本变量和引用。但是实例对象的成员变量(无论是基本类型还是引用类型)是存储如堆中的。

4.1.2 初始化

成员变量基本类型默认为0,false等,引用类型默认为null;

4.1.3 时序

变量的初始化时序在任何方法(包括构造,不包括静态方法)之前。

4.2 构造器初始化

4.2.1 目的

构造器初始化可以使用某些方法或动作来确定初值,比起定义的方式更加灵活。

4.2.2 时序

父类静态资源>子类静态资源>main方法>父类构造块>父类构造方法>子类构造块>子类构造方法

4.2.3 创建对象时序

阶段1:类加载{class文件定位>class文件加载(静态资源加载)}

阶段2:对象创建{分配存储空间>清空存储空间(默认初始化)>自定义变量初始化>对象构造器}

注意:静态资源不会主动创建,只有类加载或者对象创建的时候才会加载;

为什么清空储存空间就是默认初始化??

4.3 数组初始化

4.3.1 可变参数列表

JavaSE5之前:

Public static voidprintArray(Object[] objs){

for(Objecto:objs){

//操作

}

}

Public static void main(String[] args){

printArray(new Object[]{new Integer(12),new Float(3.14),new Double(15.22)});

printArray(new Object[]{new demo_2_1(),new Date()});

}

Object是顶级父类,通过对方法形参升级为顶级父类,保证了实际参数可以是多种类型。

JavaSE5之后:

Public static void printArray1(Object...objs){

for(Objecto:objs){

//操作

}

}

Public static void printArray2(int i,String...strs){}

Public static void main(String[] args){

printArray1(new Object[]{new Integer(12),new Float(3.14),new Double(15.22)});

printArray1(new Object[]{new demo_2_1(),new Date()});

printArray2(1,"a","b","c");

}

…代表多个个数,输出同样是提供一个类型化数组。

空类型也是合法的,如printArray1(),所以可变参数列表给重载带来了麻烦,一般编译器会使用自动包装机制匹配重载方法,但是重载方法的形参列表没有空列表的时候使用空列表方法,此时printArray()就不再合法,编译器就不知道该选择哪一个了。

5 枚举类型

枚举会将取值范围限制在拟定的范围中,适合和switch语句搭配。

//定义枚举

publicenumSpiciness{ONE,TWO,THREE,Four};

//如何使用枚举

publicstaticvoidmain(String[]args){

//想要使用枚举,需要创建一个枚举引用(本例为Spicinesss)接收枚举值

//编译器会自动为枚举类型添加方法:values()输出为依顺序的枚举值数组;ordinal()输出特定枚举值的次序

for(Spicinesss:Spiciness.values()){

System.out.println(s+"枚举顺序为"+s.ordinal());

}

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值