• 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的类,继承自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 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是从子类到基类依次查找,有关静态初始化的动作从基类到子类依次执行。

    在为所创建对象的存储空间清零后,找到继承链中最上层的基类,执行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 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
    */



     

  • 相关阅读:
    Can't remove netstandard folder from output path (.net standard)
    website项目的reference问题
    The type exists in both DLLs
    git常用配置
    Map dependencies with code maps
    How to check HTML version of any website
    Bootstrap UI 编辑器
    网上职位要求对照
    Use of implicitly declared global variable
    ResolveUrl in external JavaScript file in asp.net project
  • 原文地址:https://www.cnblogs.com/xiaoqiangzhaitai/p/5637613.html
Copyright © 2020-2023  润新知