java编程思想阅读笔记:初始化与清理

初始化

  • 构造器(constructor):就是C++中的构造函数,不写也会有一个默认的无参构造函数,会给所有成员变量进行一个初始化
  • 重载:方法名字相同,但是参数不同(最开始是为了实现构造器而设置的,后来发现可以帮助多态的实现)。
    • 为什么重载不能根据返回值的不同来确定?因为存在歧义,比如void f(); int f(); 同时存在,然后主函数写了main(){f();},此时编译器无法知道这个f()指的是哪一个函数。
    • 涉及基本类型的函数重载:基本类型能够升级,比如void f(float a)可以通过f(5)进行调用,即整数5会在调用的时候因为找不到int参数类型的函数而升级为float类型,但是类型是不能降级的。
    • this关键字
      • this其实就是对象本身,一般对象调用方法的时候,会隐式地讲第一个参数设置为对象本身。
      • 不可以出现在static修饰的静态函数中,因为静态方法可以通过类名直接调用,而不需要通过对象,因此无法传入对象。
      • this关键字可以作为返回值,从而进行类方法的级联调用
      • this关键字可以在构造器中调用构造器,从而减少初始化代码,但是只能调用一个构造器,而且绝不能在其他类方法中调用

清理:终结处理与垃圾清理

终结处理

  • finalize():并不等价于析构函数。一旦GC准备事放对象占用的存储空间,将首先调用finalize()方法,并且在下一次GC发生的时候,才会回收对象占用的内存。finalize()和析构函数相同点在于,它也会默认存在于一个类中,它是在对象即将被清理的情况下才可能会被调用,用于检查在垃圾回收前可能会出现的逻辑问题
class Book{
	boolean checkOut = false;
	Book(boolean checkout){
		checkOut = checkout;
	}
	void checkIn(){
		checkOut = false;
	}
	protected void finalize(){
		if(checkOut) System.out.println("Error: checked out");
		super.finalize();
	}
}
public class TerminationCondition{
	public static void main(){
		Book novel = new Book(true);
		novel.checkIn();
		new Book(true);		//无引用对象,会被清理
		System.gc();
	}
}
//output : Error checked out
  • gc的时候,会调用finalize函数。如果有一个Book对象在销毁前没有被checkIn那么会触发finalize()中的警告。

垃圾清理

  • 一个有趣的现象:java的垃圾清理器提高了对象在堆上分配的效率,甚至可以媲美其他语言在栈上分配的效率。在某些JVM中,堆的实现就想传送带,每分配一个对象,就会向前移动一个位置,这就使得存储空间分配速度很快,因为java的堆指针只需要简单的往后移动到未分配空间的区域即可,而不用和C++一样,找到一块足够大的空间进行分配。
  • 为什么可以像传送带一样呢,这不会导致内存溢出吗?因为java的垃圾回收会在适当的时候进行内存回收,举个例子
class mem{
	public void f(){
		while(true){
			int []a = new int[10000];
		}
	}
}
  • 这段代码是不断分配内存,换成C++程序,执行一段时间之后,就会直接崩溃,而在java中,我们会发现,内存持续增长到某个阈值的时候,就会上下起伏。
  • 所以垃圾清理(Garbage Collector, GC)是如何工作的?
    • 引用计数:计算每个对象的引用数量,如果引用数量为0了,说明该对象已经没有用处了,可以直接清理,一旦有其他引用指向了这个对象,那么引用数量+1。引用计数方法无法解决环形引用问题,如A a = new A(); A b =a; A c = b; a = c;这样,a,b,c都是垃圾,因为都没有指向有意义的地方,但是每个对象的引用都是1,导致引用计数失效。这种方法极少被JVM使用。
    • 抛弃引用计数,如何找到存活对象:从堆和静态存储区中寻找对象,如果存在对象且存在对应的引用,那么就以这些引用根,遍历找到所有相关的引用。
    • 标记-清理:每找到一个存活对象,就进行一个标记。标记完所有对象之后,对没有标记的对象进行内存的释放。好处在于不需要复制存活对象,但是剩下的堆空间是不连续的,如果想要得到连续对象,仍然需要重新分配内存。
    • 停止-复制(非后台清理):先暂停程序运行,将所有活着的对象从当前堆复制到另一个堆,然后清理当前堆的所有对象。然后,由于每个对象都换了位置,所有的引用都需要更新自己指向的地址,位于堆和静态存储区的直接引用可以直接修改(这句话什么意思,GC直接修改吗),其它非直接引用则需要在遍历的过程中才能找到对象的新地址(意思是需要手动更新?好像通过二级引用的方法可以实现不更新这个引用,但是速度相对慢)
    • java的GC能够自适应的切换停止-复制标记-清理两种方法, 当JVM看到每个对象都很稳定,停止-拷贝存在大量拷贝的情况下,会切换成标记-清理的情况,反之,当堆中存在大量碎片的情况下,又会切换成停止-拷贝的方法

参考

  • 《JAVA编程思想》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值