• Java的初始化与清理


      大家都知道,Java是站在巨人的肩上成功的,它是在C&C++的基础上进一步的开发,投入面向对象开发的怀抱。Java吸取了很多以前的教训,加入自己很多独创的方式。在程序语言发展初期,许多C程序员经常忘记初始化变量,在程序结束后也经常忘记对创建的数据类型进行释放内存,造成内存泄漏。这些"不安全"的编程方式当然需要程序员有良好的编程习惯,但如果编程语言能够加入自动清理与初始化的工作,这回大大降低开发成本。随着技术的发展,C++语言引入了构造器(constructor),即在创建对象自动调用的初识方法,Java语言采用这一方法,并加入垃圾回收器,负责自动回收用户创建的内存,进一步降低程序员的开发成本。

    Java的初始化与构造器

      创建Java的对象最普遍发的方法是使用new方法,如下所示。而创建对象必须使用构造器,构造器实际就是Java对象初始化的方法,用户可以在该方法中添加自定义初始化行为。

                     Object obj = new Object();     // 左侧为声明对象,右侧为实际创建一个对象

      构造器它是一个隐含为静态的无返回值的方法,名称与类名相同,编译期会自动调用该方法。如果用户没有创建构造器,编译期会为你自动生成一个默认构造器。总之,构造器个数至少有一个。构造器可以有多个,它可以用户自己选择如何初始化对象,这里是使用重载(Overload)的方法。如下所示:

    package com.thinkinjava.initialization;
    import static com.thinkinjava.util.Print.*;
    
    class Tree {
        int height;
        Tree() {
            print("Planting a seedling");
            height = 0;
        }
        Tree(int initialHeight) {
            height = initialHeight;
            print("Creating new Tree that is " +
                    height + " feet tall");
        }    
        void info() {
            print("Tree is " + height + " feet tall");
        }
        void info(String s) {
            print(s + ": Tree is " + height + " feet tall");
        }
    }
    
    public class Overloading {
        public static void main(String[] args) {
            for(int i = 0; i < 5; i++) {
                Tree t = new Tree(i);
                t.info();
                t.info("overloaded method");
            }
            // Overloaded constructor:
            new Tree();
        }    
    }

    Java的初始化顺序

      既然讲到Java初始化,那肯定要关注Java的初始化顺序,这涉及到一些继承的知识,首先看一个实例:

    package com.thinkinjava.multiplex;
    
    import static com.thinkinjava.util.Print.print;
    
    /**
     * 初始化顺序
     *
    */ // 形状 class Insect { private int i = 9; protected int j; private int k = priInit("Insect.k initialized"); Insect() { print("i = " + i + ",j = " + j); j = 39; } private static int x1 = priInit("static Insect.x1 initialized"); static int priInit(String s) { print(s); return 47; } } class InitOrder extends Insect { private int i = 10; private int k = priInit("InitOrder.k initialized"); public InitOrder() { print(" k = " + k); print(" j = " + j); } private static int x2 = priInit("static InitOrder.x2 initialized"); public static void main(String[] args) { print("InitOrder constructor"); InitOrder x = new InitOrder(); } } /*Output: static Insect.x1 initialized static InitOrder.x2 initialized InitOrder constructor Insect.k initialized i = 9,j = 0 InitOrder.k initialized k = 47 j = 39 */

      如上所示,当运行该Java程序时,首先访问程序入口,即InitOrder.main()方法,于是类加载器加载InitOrder.class类文件,而对它的加载过程中,通过extends关键字可知该类有个父类,于是加载该父类,如果该父类还有它自身的父类,继续加载,然后执行最高一层类的static初始化,然后是其子类,依次执行,最后所有的类的已加载完成,开始执行main方法:在main方法中开始创建对象,对象被创建之后,虚拟机会为其分配内存,主要用来存放对象的实例变量及其从父类继承过来的实例变量(即使这些从父类继承过来的实例变量有可能被隐藏也会被分配空间)。在为这些实例变量分配内存的同时,这些实例变量也会被赋予默认值。在内存中创建对象后,开始调用父类的构造器,父类的构造器能够使用super调用或被编译期自动调用,父类在执行构造器语句之前,会对父类实例变量按照次序进行初始化。父类完成父类子对象的初始化后,子类开始的顺序执行,先实例变量初始化,然后执行构造器语句。最后整个对象构造完成。

    Java的对象与清理

      Java的显著优点就是Java有良好的垃圾清理机制,C++中创建对象,使用对象后,需要使用delete操作符删除对象,就会调用对应的析构函数。而Java中没有析构函数,Java的finalize()并不是类似C++的析构函数,Java的finalize()只是用来回收本地方法(c/c++)占用的内存(调用本地方法类似free)。通常意义上来讲,Java程序员只需创建对象,而不需我们自己去销毁对象,因为垃圾回收机制会帮我们回收对象,虽然不知道什么时候回收,是否会被回收。

      然后可能会出现这种情况,类可能要在生命周期内执行一些必需的清理活动,这就需要程序员自己书写清理方法,在清理方法中必须注意清理顺序,即其顺序与初始化顺序相反,为防止出现异常,可以将清理动作放入finally中。如实例所示:

    import static com.thinkinjava.util.Print.print;
    
    /**
     * 确保正确清理
     * */
    
    // 形状
    class Shape {
        Shape(int i) {
            print("Shape constructor");
        }
    
        // 处理
        void dispose() {
            print("Shape dispose");
        }
    }
    
    class Circle extends Shape {
        Circle(int i) {
            super(i);
            print("Circle constructor");
        }
    
        void dispose() {
            print("Circle dispose");
            super.dispose();
        }
    }
    
    // 三角形
    class Triangle extends Shape {
        Triangle(int i) {
            super(i);
            print("Triangle constructor");
        }
    
        void dispose() {
            print("Triangle dispose");
            super.dispose();
        }
    }
    
    class Line extends Shape {
        private int start, end;
    
        Line(int start, int end) {
            super(start);
            this.start = start;
            this.end = end;
            print("Drawing Line:  " + start + ", " + end);
        }
    
        void dispose() {
            // 擦除线条
            print("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);
            print("Combined constructor");
        }
    
        public void dispose() {
            print("CADSystem.dispose()");
            // 清理的顺序与初始化顺序相反
            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 {
                // 程序编码与异常处理
            } 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
    Circle constructor
    Shape constructor
    Triangle constructor
    Combined constructor
    CADSystem.dispose()
    Triangle dispose
    Shape dispose
    Circle dispose
    Shape dispose
    Erasing Line: 2, 4
    Shape dispose
    Erasing Line: 1, 1
    Shape dispose
    Erasing Line: 0, 0
    Shape dispose
    Shape dispose*/

      

  • 相关阅读:
    CSS实现返回网页顶部
    jQuery实现小火箭动态返回顶部代码
    Linux目录结构介绍
    Linux常用命令及技巧
    Linux文件系统
    Linux特性
    numpy中基础函数
    restful规范
    堆栈
    三次握手与四次挥手
  • 原文地址:https://www.cnblogs.com/codingexperience/p/4868997.html
Copyright © 2020-2023  润新知