博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java基础---->对象的创建过程(初始化、析构、清理)
阅读量:6227 次
发布时间:2019-06-21

本文共 11509 字,大约阅读时间需要 38 分钟。

一、成员初始化

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 valueboolean        falsechar       byte           0short          0int            0long           0float          0.0double         0.0reference      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 initializedMugs()new Mugs() completedMug(1)Mug(2)mug1 & mug2 initializedMugs(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 mainBowl(3)Cupboard()f1(2)Creating new Cupboard() in mainBowl(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 initializedstatic Beetle.x2 initializedBeetle constructori = 9, j = 0Beetle.k initializedk = 47j = 39 */

假设有个名为Cartoon的类,继承自DrawingDrawing又继承自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 constructorDrawing constructorCartoon 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是从子类到基类依次查找,有关静态初始化的动作从基类到子类依次执行。

在为所创建对象的存储空间清零后,找到继承链中最上层的基类,执行ab两步:

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 =new Order();System.gc();如果内存没用完,它是不会浪费时间去执行垃圾回收区回复内存的。

也不会调用finalize()方法

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

order =null; System.gc()

new Order(); 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 constructorShape constructorDrawing Line: 0, 0Shape constructorDrawing Line: 1, 1Shape constructorDrawing Line: 2, 4Shape constructorDrawing CircleShape constructorDrawing TriangleCombined constructorCADSystem.dispose()Erasing TriangleShape disposeErasing CircleShape disposeErasing Line: 2, 4Shape disposeErasing Line: 1, 1Shape disposeErasing Line: 0, 0Shape disposeShape 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 0Creating Composing 0Creating Composing 1Creating Composing 2Creating Composing 3Creating Composing 4disposing Composing 0disposing Composing 1disposing Composing 2disposing Composing 3disposing Composing 4Disposing Shared 0*/

 

 

转载地址:http://unjna.baihongyu.com/

你可能感兴趣的文章
goole机器学习视频链接【学习笔记】
查看>>
查看django版本的方法
查看>>
kafka channle的应用案例
查看>>
WPF 圆角textbox
查看>>
熊彼特的创新理论:非连续性模型
查看>>
Windows10内置ubuntu子系统安装后中文环境设置
查看>>
Spring Security教程(八):用户认证流程源码详解
查看>>
由浅入深:CNN中卷积层与转置卷积层的关系
查看>>
Solve Error: "errcode": 40016, "errmsg": "invalid button size hint"
查看>>
EF Core Fluent API
查看>>
MAC 设置环境变量path的几种方法
查看>>
JVM垃圾收集器(2)
查看>>
SpringBoot之hello world!
查看>>
Socket拆包和解包
查看>>
工作之忠、智、勇
查看>>
电子书下载:Beginning Nokia Apps Development: Using MeeGo, Mobile QT and OpenSymbian
查看>>
mysql 5.0存储过程学习总结
查看>>
matlab练习程序(Ritter‘s最小包围圆)
查看>>
SQL存储过程教程
查看>>
最详细的临时表,表变量的对比
查看>>