• 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
    */



     

  • 相关阅读:
    百度地图设置div样式宽高为百分比不显示地图
    C#添加修改控件css样式
    斐波那契查找原理详解与实现
    JavaWeb 如何在web.xml中配置多个servlet
    eclipse中添加tomcat ServerName 无法输入
    java 面试题
    JSON 转 对象
    Eclipse 导入Maven 项目报错
    Mybatis 中 update 语句 动态 语句
    oracle 将当前系统时间戳插入timestamp字段
  • 原文地址:https://www.cnblogs.com/xiaoqiangzhaitai/p/5637612.html
Copyright © 2020-2023  润新知