JAVA中的引用与对象详解
Thinking in Java 一书中提到,引用和对象就像瑶控器和电视机。用瑶控器(引用)来操作电视机(对象),想换频道什么的直接操作瑶控器就可以了,瑶控器再来调控电视机。如果你在房间里面走动,同时还想操作电视换频道,你只需要携带瑶控器就可以了。我觉得这个比较非常好,引用是用来操作对象的,对象是由你来创建的。通常用new关键字来创建一个对象。那么这些对象是怎样存储的,内存又是怎样分配的呢?
存储在什么地方?
1.寄存器(register):由于寄存器是在CPU内部的,所以它的速度最快,但是数量有限,所以由编译器根据需求进行分配。
2.栈(stack):位于通用RAM中,通过栈指针的移动来分配和释放内存,指针向下移动分配新的内存;指针向上移动则释放内存。速度仅次于寄存器。创建程序时,Java编译器必须知道存储在栈内所有数据的确切大小和生命周期,因为它必须生成相应的代码,以便上下移动栈指针,这就限制了程序的灵活性。所以java中的对象并不存放在栈当中,但对象的引用存放在栈中。
3.堆(heap):也是位于RAM中的内存池,用于存放所有的JAVA对象。编译器不需要知道要从堆里分配多少存储区域,也不需要知道存储的数据在堆里面存活多长时间,因此堆要比栈灵活很多。当你new创建一个对象时,编译器会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用栈进行存储存储需要更多的时间。
4.静态存储(static storage):这里的“静态”是指“在固定的位置”(也在RAM里)。静态存储里存放程序运行时一直存在的数据。你可用关键字static来标识一个对象的特定元素是静态的,即存放类中的静态成员,但JAVA对象本身从来不会存放在静态存储空间里。
5. 常量存储(constant storage):存放字符串常量和基本类型常量(public static final)。常量值通常直接存放在程序代码内部,它们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分分割离开,所以在这种情况下,可以选择将其放在ROM中。
简单描述下垃圾回收机制
垃圾回收回收的是无任何引用的对象占据的内存空间(堆)而不是对象本身,要注意以下3点:
1)对象可能不会被回收,即垃圾回收不一定会执行;
2)垃圾回收并不等于析构;
3)垃圾回收只与内存有关。
引用计数器:一种简单但是速度很慢的垃圾回收策略。即每个对象都有一个引用计数器,当有引用连接至对象时计数器加1;当引用离开时计数器减1。垃圾回收器会在含有全部对象的列表中遍历,发现某个对象的引用计数器为0时,就释放其占用的内存。
优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序不被长时间打断的实时环境比较有利。
缺点:无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0。
自适应、分代的、停止——复制、标记——清扫 垃圾回收方法:
停止——复制:先暂停程序的运行,然后将所有活的对象从当前堆复制到另一个堆,没有被复制的都是垃圾。当对象从一个堆复制到另一个堆,它们的排列是一个挨着一个的,所以新堆保持紧凑排列。
标记——清扫:遍历所有的引用,找出所有活的对象,然后对它们进行标记,这个过程不会回收任何对象,只有全部标记工作完成时才开始清除工作。没有被标记的对象将会被释放,不发生任何复制动作,所以剩下的堆空间不是连续的。
创建了几个对象?
String s="abc"; 创建了几个对象?
毫无疑问,这里面只创建了一个对象——“abc";
String s1="abc"; String s2=s1;创建了几个对象?
仍然只有一个对象——“abc";
String s1="abc"; String s2=”abc";创建了几个对象?
这里仍然只有一个对象——“abc";
String s="abc"+"def";创建了几个对象?
注意,这里创建了三个对象:“abc"、”def"、“abcdef";
String s=new String("abc");创建了几个对象?
大家也都知道是两个对象。实际上是"abc"本身就是文字池中的一个对象,在运行new String()时,把文字池即pool中的字符串"abc"复制到堆中,并把这个对象的应用交给s,所以创建了两个String对象,一个在pool中,一个在堆中。
String s1=new String("abc");String s2=new String("abc");创建了几个对象?
三个对象。"abc"是文字池中的一个对象,然后又在堆中用new String()创建了两个对象。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!