java 析构对象_java基础---->对象的创建过程(初始化、析构、清理)

一、成员初始化

1、方法的成员局部变量,以编译时错误保证初始化。

2、类的每一个基本类型数据成员会保证有一个初始值。

public class InitialValues {

boolean t;

char c;

byte b;

short s;

int i;

long l;

float f;

double d;

InitialValues reference;

void printInitialValues() {

System.out.println("Data type Initial value");

System.out.println("boolean " + t);

System.out.println("char " + c);

System.out.println("byte " + b);

System.out.println("short " + s);

System.out.println("int " + i);

System.out.println("long " + l);

System.out.println("float " + f);

System.out.println("double " + d);

System.out.println("reference " + reference);

}

public static void main(String[] args) {

new InitialValues().printInitialValues();

}

} /* Output:

Data type Initial value

boolean false

char

byte 0

short 0

int 0

long 0

float 0.0

double 0.0

reference null

*/

3、指定初始化:在定义变量的地方为其赋值

4、构造器初始化:在构造方法里面初始化。

在一个类里,初始化的顺序是由变量在类内的定义顺序决定的。即使变量定义大量遍布于方法定义的中间,那些变量仍会在调用任何方法之前得到初始化——在构建器调用之前。

若数据是静态的(static),那么同样的事情就会发生;如果它属于一个基本类型,而且未对其初始化,就会自动获得自己的标准基本类型初始值;如果它是指向一个对象的句柄(引用),那么除非新建一个对象,并将句柄(引用)同它连接起来,否则就会得到一个空值(NULL)。

二、静态块

静态块:使用static关键字声明的代码块,静态代码块在第一次加载类时执行,而且只执行一次,当访问类的静态属性或者方法,创建类对象,或者执行该类的main方法之前,都要加载类。可以用来为静态变量初始化。在主类中定义的静态块将优先于主方法main()执行。而且可以发现静态块优先于构造块执行.

class Cup {

Cup(int marker) {

System.out.println("Cup(" + marker + ")");

}

void f(int marker) {

System.out.println("f(" + marker + ")");

}

}

class Cups {

static Cup cup1;

static Cup cup2;

static {

cup1 = new Cup(1);

cup2 = new Cup(2);

}

Cups() {

System.out.println("Cups()");

}

}

public class ExplicitStatic {

static {

System.out.println("静态块在类加载时候执行");

}

public static void main(String[] args) {

System.out.println("Inside main()");

Cups.cup1.f(99);

}

} /*

* Output:

静态块在类加载时候执行

Inside main()

Cup(1)

Cup(2)

f(99)

*/

可以使用静态块“替代”掉main方法。

static {

System.out.println("HelloWorld!!!") ;

System.exit(1);

}

三、非静态实例初始化(构造块)

构造块:在一个类中定义的代码块,构造块会优先于构造方法执行,而且每当一个新的实例化对象产生时,都会调用构造块,会调用多次。用于初始化对象的非静态变量。

class Mug {

Mug(int marker) {

System.out.println("Mug(" + marker + ")");

}

void f(int marker) {

System.out.println("f(" + marker + ")");

}

}

public class Mugs {

Mug mug1;

Mug mug2;

{

mug1 = new Mug(1);

mug2 = new Mug(2);

System.out.println("mug1 & mug2 initialized");

}

Mugs() {

System.out.println("Mugs()");

}

Mugs(int i) {

System.out.println("Mugs(int)");

}

public static void main(String[] args) {

System.out.println("Inside main()");

new Mugs();

System.out.println("new Mugs() completed");

new Mugs(1);

System.out.println("new Mugs(1) completed");

}

} /*Output:

Inside main()

Mug(1)

Mug(2)

mug1 & mug2 initialized

Mugs()

new Mugs() completed

Mug(1)

Mug(2)

mug1 & mug2 initialized

Mugs(int)

new Mugs(1) completed

*/

四、Java对象的创建过程

4.1不涉及继承

假设有个名为Dog的类1.当首次创建型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。2.然后载入Dog.class(这将创建一个Class对象),有关静态初始化的动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。3.当你用newDog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。4.这块存储空间会被清零,这就自动地将Dog中的所有基本类型数据设置成了默认值(对数字来说就是0,对布尔型和字符型也相同),而引用则被置成了null。5.执行所有出现于域定义处的初始化动作。6.执行构造器。

例子如下:

class Bowl {

Bowl(int marker) {

System.out.println("Bowl(" + marker + ")");

}

void f1(int marker) {

System.out.println("f1(" + marker + ")");

}

}

class Table {

static Bowl bowl1 = new Bowl(1);

Table() {

System.out.println("Table()");

bowl2.f1(1);

}

void f2(int marker) {

System.out.println("f2(" + marker + ")");

}

static Bowl bowl2 = new Bowl(2);

}

class Cupboard {

Bowl bowl3 = new Bowl(3);

static Bowl bowl4 = new Bowl(4);

Cupboard() {

System.out.println("Cupboard()");

bowl4.f1(2);

}

void f3(int marker) {

System.out.println("f3(" + marker + ")");

}

static Bowl bowl5 = new Bowl(5);

}

public class StaticInitialization {

public static void main(String[] args) {

System.out.println("Creating new Cupboard() in main");

new Cupboard();

System.out.println("Creating new Cupboard() in main");

new Cupboard();

table.f2(1);

cupboard.f3(1);

}

static Table table = new Table();

static Cupboard cupboard = new Cupboard();

} /* Output:

Bowl(1)

Bowl(2)

Table()

f1(1)

Bowl(4)

Bowl(5)

Bowl(3)

Cupboard()

f1(2)

Creating new Cupboard() in main

Bowl(3)

Cupboard()

f1(2)

Creating new Cupboard() in main

Bowl(3)

Cupboard()

f1(2)

f2(1)

f3(1)

*/

4.2涉及了继承的情况:

class Insect {

private int i = 9;

protected int j;

Insect() {

System.out.println("i = " + i + ", j = " + j);

j = 39;

}

private static int x1 = printInit("static Insect.x1 initialized");

static int printInit(String s) {

System.out.println(s);

return 47;

}

}

public class Beetle extends Insect {

private int k = printInit("Beetle.k initialized");

public Beetle() {

System.out.println("k = " + k);

System.out.println("j = " + j);

}

private static int x2 = printInit("static Beetle.x2 initialized");

public static void main(String[] args) {

System.out.println("Beetle constructor");

Beetle b = new Beetle();

}

} /* Output:

static Insect.x1 initialized

static Beetle.x2 initialized

Beetle constructor

i = 9, j = 0

Beetle.k initialized

k = 47

j = 39

*/

假设有个名为Cartoon的类,继承自Drawing,Drawing又继承自Art

class Art {

static {System.out.println("Art 的静态块");}

Art() {

System.out.println("Art constructor");

}

}

class Drawing extends Art {

static {System.out.println("Drawing的静态块");}

Drawing() {

System.out.println("Drawing constructor");

}

}

public class Cartoon extends Drawing {

static {System.out.println("Cartoon的静态块");}

public Cartoon() {

System.out.println("Cartoon constructor");

}

public static void main(String[] args) {

Cartoon x = new Cartoon();

}

}

/*Output:

Art 的静态块

Drawing的静态块

Cartoon的静态块

Art constructor

Drawing constructor

Cartoon constructor

*/

1.当首次创建型为Cartoon的对象时,Java解释器查找类路径,定位Cartoon.class文件。

2.Java解释器会根据Cartoon.class定位其基类Drawing.class、再根据Drawing.class定位到基类Art.class文件,有关静态初始化的动作从基类到子类依次执行。

3.当你用new Cartoon()创建对象的时候,首先将在堆上为Cartoon对象(包括其基类Drawing和Art中的域)分配足够的存储空间。

4.这块存储空间会被清零,这就自动地将Cartoon中的所有基本类型数据(包括其基类Drawing和Art中的)设置成了默认值(对数字来说就是0,对布尔型和字符型也相同),而引用(包括其基类Drawing和Art中的)则被置成了null。

5.执行基类Art中所有出现于域定义处的初始化动作。

6.执行基类Art构造器。

7.执行基类Drawing中所有出现于域定义处的初始化动作。

8.执行基类Drawing构造器。

9.执行子类Cartoon中所有出现于域定义处的初始化动作。

10.执行子类Cartoon构造器。

即:class是从子类到基类依次查找,有关静态初始化的动作从基类到子类依次执行。

在为所创建对象的存储空间清零后,找到继承链中最上层的基类,执行a、b两步:a.执行其出现在域定义处的初始化动作b.然后再执行其构造器然后从基类到子类依次执行这两步操作。

五、析构函数finalize()

5.1  finalize()方法

一旦垃圾回收期准备释放对象所占的存储空间,首先调用其finalize()方法

1、  对象可能不被垃圾回收

只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。如果程序执行结束,垃圾回收器一直没有释放你创建的对象的存储空间,则随着程序退出,那些资源也会交还给操作系统。因为垃圾回收本身也要开销,如果不使用它,那就不用支付这部分开销了。

2、  垃圾回收并不等于析构,垃圾回收器不能替代析构函数(如在finalize()加入擦擦屏幕图像的功能)

3、  垃圾回收只与对象占用的内存有关。如可以通过finalize释放通过native方法获得的内存。

class Order {

protectedvoid finalize() throws Throwable {

super.finalize();

System.out.println("调用析构方法");

}

}

publicclass TestFinalize {

publicstatic void main(String[] args) {

Order order =new Order();

order = null;

new Order();

System.gc(); // 会打印

for (int i = 0; i < 100; i++) {// 不会输出,因为内存没用完垃圾回收器不起作用,当改成i<10000000时候会打印,

Order order1 =new Order();

}

}

}

/*

* Output调用析构方法调用析构方法

*/

1、只有内存用完了,垃圾回收器起作用,才会调用finalize()方法

Order order =newOrder();System.gc();如果内存没用完,它是不会浪费时间去执行垃圾回收区回复内存的。

也不会调用finalize()方法

2、手动调用System.gc()  除非指向堆空间的引用为0,才会调用finalize()方法

order =null; System.gc()

newOrder();System.gc()

5.2、Finalize可能的使用方式:

用于对象总结条件的验证

class Book {

boolean checkedOut =false;

Book(boolean checkOut) {

checkedOut = checkOut;

}

void checkIn() {

checkedOut = false;

}

protectedvoid finalize() {

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();

}

}/* Output:

Error: checked out

*/

5.3编写自己的清理方法

一旦涉及到垃圾回收,能够信赖的事情就不多了。垃圾回收器可能永远无法调用,即使被调用,他也可能以任何他想要的顺序来回收对象。最好的办法是出了内存外,不能依靠垃圾回收去做任何事。如果需要清理,最好编写自己的清理方法,但不要使用finalize()。

class Shape {

Shape(int i) {

System.out.println("Shape constructor");

}

void dispose() {

System.out.println("Shape dispose");

}

}

class Circle extends Shape {

Circle(int i) {

super(i);

System.out.println("Drawing Circle");

}

void dispose() {

System.out.println("Erasing Circle");

super.dispose();

}

}

class Triangle extends Shape {

Triangle(int i) {

super(i);

System.out.println("Drawing Triangle");

}

void dispose() {

System.out.println("Erasing Triangle");

super.dispose();

}

}

class Line extends Shape {

private int start, end;

Line(int start, int end) {

super(start);

this.start = start;

this.end = end;

System.out.println("Drawing Line: " + start + ", " + end);

}

void dispose() {

System.out.println("Erasing Line: " + start + ", " + end);

super.dispose();

}

}

public class CADSystem extends Shape {

private Circle c;

private Triangle t;

private Line[] lines = new Line[3];

public CADSystem(int i) {

super(i + 1);

for (int j = 0; j < lines.length; j++)

lines[j] = new Line(j, j * j);

c = new Circle(1);

t = new Triangle(1);

System.out.println("Combined constructor");

}

public void dispose() {

System.out.println("CADSystem.dispose()");

// The order of cleanup is the reverse

// of the order of initialization:

t.dispose();

c.dispose();

for (int i = lines.length - 1; i >= 0; i--)

lines[i].dispose();

super.dispose();

}

public static void main(String[] args) {

CADSystem x = new CADSystem(47);

try {

// Code and exception handling...

} finally {

x.dispose();

}

}

} /* Output:

Shape constructor

Shape constructor

Drawing Line: 0, 0

Shape constructor

Drawing Line: 1, 1

Shape constructor

Drawing Line: 2, 4

Shape constructor

Drawing Circle

Shape constructor

Drawing Triangle

Combined constructor

CADSystem.dispose()

Erasing Triangle

Shape dispose

Erasing Circle

Shape dispose

Erasing Line: 2, 4

Shape dispose

Erasing Line: 1, 1

Shape dispose

Erasing Line: 0, 0

Shape dispose

Shape dispose

*/

5.4 对象被共享时,清理时使用引用计数判断

成员对象中存在一个或多个对象共享的情况,必须使用引用计数来跟踪访问着共享对象的对象数量

class Shared {

private int refcount = 0;

private static long counter = 0;

private final long id = counter++;

public Shared() {

System.out.println("Creating " + this);

}

public void addRef() {

refcount++;

}

protected void dispose() {

if (--refcount == 0)

System.out.println("Disposing " + this);

}

public String toString() {

return "Shared " + id;

}

}

class Composing {

private Shared shared;

private static long counter = 0;

private final long id = counter++;

public Composing(Shared shared) {

System.out.println("Creating " + this);

this.shared = shared;

this.shared.addRef();

}

protected void dispose() {

System.out.println("disposing " + this);

shared.dispose();

}

public String toString() {

return "Composing " + id;

}

}

public class ReferenceCounting {

public static void main(String[] args) {

Shared shared = new Shared();

Composing[] composing = { new Composing(shared), new Composing(shared),

new Composing(shared), new Composing(shared),

new Composing(shared) };

for (Composing c : composing)

c.dispose();

}

}

/*Output:

Creating Shared 0

Creating Composing 0

Creating Composing 1

Creating Composing 2

Creating Composing 3

Creating Composing 4

disposing Composing 0

disposing Composing 1

disposing Composing 2

disposing Composing 3

disposing Composing 4

Disposing Shared 0

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值