Java 初始化与清理

来源:互联网 发布:淘宝删差评链接 编辑:程序博客网 时间:2024/05/21 08:49

一、构造器


1. 什么是构造器?
创建对象时被自动调用的特殊方法。

2. 使用构造器的目的:确保对象初始化。

3. 构造器的特征:
构造器名称与类名相同
它不含返回值类型的定义,不能返回一个值
构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading

4. 默认构造器(无参构造器):
每个类没有显示写出构造器,会默认产生一个无参构造。
如果显示的写出一个有参构造,不会产生默认的无参构造。
父类仅有有参构造,子类必须构造中显示调用
如果是子类的话,默认的无参构造包含一个super()方法。


二、方法重载

1. 方法是给某个动作取得名字。

2. 如何区分重载,构造器重载?
方法名相同,只要方法的参数类型或者个数不同,就被认定为是重载方法。

3. 基本类型的重载
方法传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际数据类型就会被提升。
方法传入的数据类型(实际参数类型)大于方法中声明的形式参数类型,实际数据类型就会被窄化处理。

void methodName(long x) { System.out.println( "Method long " ); }
void methodName(float x) { System.out.println( "Method float " ); }
void methodName(double x) { System.out.println( "Method double " ); }
以上声明的三个方法,如果执行以下语句具体会执行哪个方法呢?
methodName(5); // 5是int类型
执行结果是:Method long ,传入的5是int类型小于方法中声明的形参类型,执行时实际类型就会被提升,int类型是单精度的所以不会被提升为双精度的float或double,最终执行long形参的方法。


三、this关键字

this表示调用属性或者方法的那个对象。
类内部调用自身属性或者方法无需this。
链式编程。

表示:调用方法的那个对象。“这个对象”, “当前对象”,对当前对象的引用
a.method();
b.method();
其实是调用a的对象的method方法
this 构造器中调用构造器。


四、static
静态方法内部,不能调用非静态方法。(特例)
不创建对象的情况下,通过类本身调用static方法(多用于工具类,类似于全局方法)、或常量(类似于全局变量)
static的值可以被修改吗?

可参考  《Java static关键字》

五、清理:终结处理和垃圾回收

1. GC是什么?GC的目的是什么?
GC是垃圾收集的意思(Gabage Collection)。目的:清理垃圾避免垃圾超出可容纳空间(内存泄露)。

2. java中会存在内存泄漏吗?
会出现内存泄露,自己实现堆载的数据结构时有可能会出现内存泄露


3. 垃圾回收器的基本原理是什么?
摘自《Java编程思想》
打个比方,您可以把C++里的堆想象成一个院子,里面每个对象都负责管理自己的地盘。一段时间以后,对象可能被销毁,但地盘必须加以重用。在某些Java虚拟机中,堆的实现截然不同:它更像一个传送带,每分配一个新对象,它就往前移动一格。

这意味着对象存储空间的分配速度非常快。Java的“堆指针”只是简单地移动到尚未分配的区域,其效率比得上C++在堆栈上分配空间的效率。

您也许已经意识到了,Java中的堆未必完全像传送带那样工作。要真是那样的话,势必会导致频繁的内存页面调度——将其移进移出硬盘,因此会显得需要拥有比实际需要更多的内存。页面调度会显著地影响性能,最终,在创建了做够多的对象之后,内存资源将耗尽。其中的秘密在于垃圾回收器的介入。

当它工作时,将一面回收空间,一面使堆中的对象紧凑排列,这样“堆指针”就可以很容易移动到更靠近传送带的开始处,也就尽量避免了页面错误。通过垃圾回收器对对象重新排列,实现了一种高速的、有无限空间可供分配的堆模型。


4. 垃圾回收器2种回收机制
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。
通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。

回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
停止-复制
标记-清理
 
停止-复制方式步骤:
先暂停程序的运行(所以它不属于后台回收模式),然后将所有存活的对象从当前堆复制到另一个堆,没有被复制的全部都是垃圾。
当对象被复制到新堆时,它们是一个挨着一个的,所以新堆保持紧凑排列,然后就可以按前述方法简单、直接地分配新空间了。
把引用影响到新堆中的相应位置。

此方式效率会降低的原因:
1)一个待清理的堆,一个用于放置所有非垃圾对象的堆,所以需要多一倍的空间。
2)问题在于复制。程序进入稳定状态之后,可能只会产生少量垃圾,甚至没有垃圾。 


标记-清理方式步骤:
“标记-清扫”所依据的思路同样是从堆栈和静态存储区出发,遍历所有的引用,进而找出所有存活的对象。每当它找到一个存活对象,就会给对象设一个标记,这个过程中不会回收任何对象。只有全部标记工作完成的时候,清理动作才会开始。在清理过程中,没有标记的对象将被释放,不会发生任何复制动作。所以剩下的堆空间是不连续的,垃圾回收器要是希望得到连续空间的话,就得重新整理剩下的对象。

5. 垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

6. finalize方法
一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
finalize方法存在用途,仅用于处理非java创建使用的空间,例如:Java通过JNI其中C/C++分配的内存空间,可以把此方法作为析构函数,防止清理内存空间的操作。

 
SoftReference
WeakReference

资料:
《Java进阶10 内存管理与垃圾回收》
http://www.cnblogs.com/vamei/archive/2013/04/28/3048353.html



六、成员初始化


class Insect {  private int t = printInit("init SuperClass not static attribute");  private int i = 9;  protected int j;  Insect() {    System.out.println("execute SuperClass constructor.");System.out.println("i = " + i);    System.out.println("j = " + j +"\n --初始化父类,先初始非静态变量后构造方法\n");    j = 39;  }  private static int x1 = printInit("init SuperClass static attribute");  static int printInit(String s) {    System.out.println(s);    return 47;  }}public class Beetle extends Insect {  private int k = printInit("init SubClass not static attribute");  public Beetle() {    System.out.println("execute SubClass constructor.");    System.out.println("k = " + k);    System.out.println("j = " + j +"\n --初始化子类,先初始非静态变量后构造方法");  }  private static int x2 = printInit("init SubClass static attribute\n --首先以先父后子类顺序初始化static变量结束\n");  public static void main(String[] args) {    System.out.println("init SubClass constructor\n --下面new Beetle()开始调用子类构造器\n");    Beetle b = new Beetle();  }} 

输出结果:
init SuperClass static attributeinit SubClass static attribute --首先以先父后子类顺序初始化static变量结束init SubClass constructor --下面new Beetle()开始调用子类构造器init SuperClass not static attributeexecute SuperClass constructor.i = 9j = 0 --初始化父类,先初始非静态变量后构造方法init SubClass not static attributeexecute SubClass constructor.k = 47j = 39 --初始化子类,先初始非静态变量后构造方法

结论:
1. 先初始化所有父类子类static属性、先后顺序按继承体系先初始化父类static属性,再初始化子类static属性。
2. 再依照继承体系,由上(父类)至下(子类)逐层进行初始化。
3. 每一层都是先初始化当前所有属性、再调用当前构造器。



七、数组初始化

可变参数列表


八、枚举类型




九、参考资料:

《Java 编程思想 4》



2014-12-25 与 《Java 初始化与销毁》 合并


0 0
原创粉丝点击