java基础---->对象的创建过程(初始化、析构、清理)
来源:互联网 发布:zynq linux smp 编辑:程序博客网 时间:2024/05/21 19:16
一、成员初始化
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的类,继承自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 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是从子类到基类依次查找,有关静态初始化的动作从基类到子类依次执行。
在为所创建对象的存储空间清零后,找到继承链中最上层的基类,执行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 =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*/
- java基础---->对象的创建过程(初始化、析构、清理)
- Java 创建对象时的初始化过程
- java对象的初始化和清理
- Java对象创建和初始化过程,处理字符串的机制
- Java:对象创建和初始化过程
- Java:对象创建和初始化过程
- JAVA中对象创建和初始化过程
- JAVA中对象创建和初始化过程
- JAVA中对象创建和初始化过程
- JAVA中对象创建和初始化过程
- Java:对象创建和初始化过程
- Java:对象创建和初始化过程
- java对象创建过程/初始化顺序
- Java:对象创建和初始化过程
- Java:对象创建和初始化过程
- java对象创建过程及初始化顺序
- Java 对象初始化与清理
- Java基础:初始化和清理
- 堆 栈 区别
- struts2核心工作流程与原理
- c# 获取网页源码
- JS判断扫描枪扫描与人工输入值问题
- python高阶函数
- java基础---->对象的创建过程(初始化、析构、清理)
- g++编译使用静态程序库
- JAVA类集----SortedSet接口
- ubuntu配置TFTP服务器
- 可用性研究
- linux内核及驱动开发中有关__init,__exit和__initdata的用法
- ubuntu 用wine卸载wine安装的应用
- Java I/O工作机制及优化
- linux 监视文件系统inotify 测试