this关键字,垃圾回收
一 this关键字
1 自己的理解是:
1.1 出现在类创建之初的构造器或方法中,而一般不再类具体实现中出现,也不会出现在静态方法中。
1.2 字面意思是当前对象的引用,你可以像对待其他引用一样对待这个引用。
2 一些特殊的用法:
2.1 返回this
public class Leaf { int i = 0; Leaf increment() { i++; return this; } void print() { System.out.println("i = " + i); } public static void main(String[] args) { Leaf x = new Leaf(); x.increment().increment().increment().print(); } }
输出结果为3,每调用一次increment(),返回的对象的元素i加一,最后打印。
2.3 构造器中调用构造器
public class Flower { int petalCount = 0; String s = "initial value"; Flower(int petals) { petalCount = petals; System.out.println("Constructor w/ int arg only, petalCount = " + petalCount); } Flower(String ss) { System.out.println("Constructor w/ string arg only, s = " + ss); s = ss; } Flower(String s, int petals) { this(petals); //- this(s); // Can't call two! this.s = s; // Another use of "this" System.out.println("String & int args"); } Flower() { this("hi", 47); System.out.println("no-arg constructor"); } void printPetalCount() { //- this(11); // Not inside constructor! System.out.println("petalCount = " + petalCount + " s = " + s); } public static void main(String[] args) { Flower x = new Flower(); x.printPetalCount(); } }
在构造器中运用this调用构造器可以实现更多奇怪的想法。
注意,只能在构造器中调用构造器一次。
结果:
Constructor w/ int arg only, petalCount = 47 String & int args no-arg constructor petalCount = 47 s = hi
static简单说明:静态方法是为类而创建的,不需要任何对象。事实上,这就是静态方法的主要目的,静态方法看起来就像全局方法一样,但是 Java 中不允许全局方法。
使用静态方法,因为不存在 this,所以你没有向一个对象发送消息。不是面向对象的。
如果你发现代码中出现了大量的 static 方法,就该重新考虑自己的设计了。static 的概念很实用,许多时候都要用到它。
二 垃圾回收
1 .finalize()方法
Java垃圾回收器只能回收通过new分配的对象,除此之外需要使用finalize()方法。
一般在Java使用本地方法时调用,本地方法支持调用c和c++的代码,这些语言可能有垃圾回收器无法回收的对象。
如果 Java 虚拟机(JVM)并未面临内存耗尽的情形,它可能不会浪费时间执行垃圾回收以恢复内存。
使用示范:
// housekeeping/TerminationCondition.java // Using finalize() to detect a object that // hasn't been properly cleaned up import onjava.*; class Book { boolean checkedOut = false; Book(boolean checkOut) { checkedOut = checkOut; } void checkIn() { checkedOut = false; } @Override protected void finalize() throws Throwable { if (checkedOut) { System.out.println("Error: checked out"); } // Normally, you'll also do this: // super.finalize(); // Call the base-class version } } public class TerminationCondition { public static void main(String[] args) { Book novel = new Book(true); // Proper cleanup: novel.checkIn(); // Drop the reference, forget to clean up: new Book(true); // Force garbage collection & finalization: System.gc(); new Nap(1); // One second delay } }
输出:Error: checked out
2 垃圾回收器工作方式
2.1 Java堆工作方式
Java堆拥有和c++语言栈差不多的读写速度。
原因:它类似一个传送带,每分配一个新对象,它就向前移动一格。这意味着对象存储空间的分配速度特别快。Java 的"堆指针"只是简单地移动到尚未分配的区域,所以它的效率与 C++ 在栈上分配空间的效率相当。
但是不完全是传送带,那样会导致频繁的页面调度,最终内存会耗尽。
解决:垃圾回收器的介入,当它工作时,一边回收内存,一边使堆中的对象紧凑排列,这样"堆指针"就可以很容易地移动到更靠近传送带的开始处,也就尽量避免了页面错误。
2.2 引用计数
原理:每个对象中含有一个引用计数器,每当有引用指向该对象时,引用计数加 1。当引用离开作用域或被置为 null 时,引用计数减 1。垃圾回收器会遍历含有全部对象的列表,当发现某个对象的引用计数为 0 时,就释放其占用的空间。
缺点:如果对象之间存在循环引用,那么它们的引用计数都不为 0,就会出现应该被回收但无法被回收的情况。(形成闭环)
该方法几乎没有在任何Java虚拟机中使用。
2.3 停止-复制
原理:存活对象追溯到栈或静态存储区,每次从栈或静态存储区出发,遍历所有的引用,这个引用链条可能会穿过数个对象层次,你将会发现所有"活"的对象。形成一个网,网上的都是活得,不在网上的就会被垃圾回收。
优点:很好解决对象间循环引用的问题,这些对象不会被发现。
在此方式下形成停止-复制,需要先暂停程序运行,将活的对象复制到另一个堆/空块,此时还会重新紧密排列,可以按照前面描述的那样简单、直接地分配新空间。
缺点:效率低,所有指向它的引用都必须修正。
1,得有两个堆,然后在这两个分离的堆之间来回折腾,得维护比实际需要多一倍的空间。某些 Java 虚拟机对此问题的处理方式是,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之间。
2,程序稳定复制减少,垃圾减少或无,此时复制浪费时间占用资源。解决:要是没有新垃圾产生,就会转换到另一种模式“标记-清扫”。
2.4 标记-清扫
原理,遍历标记存活对象,但不回收,遍历完统一处理,未标记直接清理,无复制过程。
缺点,剩下的堆不连续,要连续空间就需要重新整理剩下的对象。
2.5 注意
1 垃圾回收不是后台处理,而是需要程序停止,优先级很低。
2 当可用内存较低时,垃圾回收器会暂停程序。在具体实施时,标记清扫和停止复制会根据垃圾回收效率自适应切换。
3 "即时"(Just-In-Time, JIT)编译器。Java虚拟机提高速度的附加技术,可以把程序全部或部分翻译成本地机器码,所以不需要 JVM 来进行翻译,因此运行得更快。
当需要装载某个类(通常是创建该类的第一个对象)时,编译器会先找到其 .class 文件,然后将该类的字节码装入内存。你可以让即时编译器编译所有代码,但这种做法有两个缺点:一是这种加载动作贯穿整个程序生命周期内,累加起来需要花更多时间;二是会增加可执行代码的长度(字节码要比即时编译器展开后的本地机器码小很多),这会导致页面调度,从而一定降低程序速度。另一种做法称为惰性评估,意味着即时编译器只有在必要的时候才编译代码。这样,从未被执行的代码也许就压根不会被 JIT 编译。新版 JDK 中的 Java HotSpot 技术就采用了类似的做法,代码每被执行一次就优化一些,所以执行的次数越多,它的速度就越快。
参考:On Java 8

浙公网安备 33010602011771号