详解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*/

以上就是详解Java的初始化与清理的详细内容,更多关于Java的初始化与清理的资料请关注我们其它相关文章!

(0)

相关推荐

  • 如何批量清理系统临时文件(语言:C#、 C/C++、 php 、python 、java )

    语言之争由来已久,下面做一些IO实验(遍历9G多的文件,批量删除),尽量用事实来比较谁优谁劣.操作系统:win7 64 位,文件包大小:9.68G. 一.语言:C# 开发环境:vs 2013 代码总行数:43行 耗时:7秒 代码: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; n

  • 6种方法初始化JAVA中的list集合

    List 是 Java 开发中经常会使用的集合,你们知道有哪些方式可以初始化一个 List 吗?这其中不缺乏一些坑,今天栈长我给大家一一普及一下. 1.常规方式 List<String> languages = new ArrayList<>(); languages.add("Java"); languages.add("PHP"); languages.add("Python"); System.out.println

  • Java类加载连接和初始化原理解析

    1.当程序使用某个类时,JVM将会完成以下这三个步骤 2.连接 1)验证 验证是否是合法的字节码文件.验证JDK版本是否正确等. 2)准备 给成员变量(类变量/静态变量)赋默认值 把常量(final)等值在方法区的常量池中给准备好. 3)解析 虚拟机常量池内的符号引用(常量名)替换为引用(地址)的过程 3.初始化 <clinit> 类初始化 <clinit> 类初始化由两部分组成: (1)静态变量的显示初始化代码,赋值代码 (2)静态代码块 (1) 和 (2) 的顺序从上往下 当一

  • Java类的初始化顺序知识点总结

    对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序依次是(静态变量.静态初始化块)>(变量.初始化块)>构造器. 初始化顺序图示: 我们也可以通过下面的测试代码来验证这一点: package com.trs.oop; /** * 类的初始化顺序 * 静态变量->静态初始化块->变量->初始化块->构造器 * @author xiayunan * @date 2018年7月5日 * */ public class InitialOrderTest { /

  • Java初始化List方法代码实例

    List指的是集合.<>是泛型,里面指定了这个集合中存放的是什么数据. 比如有一个学生类Student,Student里面包含了学生的一些信息.这样每一个Student对象就代表了一个学生.此时List<Student>就代表这个集合中存放了很多个学生对象,这个集合就像一个班级一样. 第一种 /** * 第一种方式 * 常规方式 */ @Test public void one(){ List<String> languages = new ArrayList<&

  • java实现清理DNS Cache的方法

    本文实例讲述了java实现清理DNS Cache的方法.分享给大家供大家参考.具体分析如下: 一.测试环境 OS:Windows7 x64 JDK:1.6.0_45 二.本人找到四种方式清理jvm的DNS缓存,大家可以根据自己的情况选用. 1. 在首次调用InetAddress.getByName()前,设置java.security.Security.setProperty("networkaddress.cache.ttl", "0"); 2. 修改jre/li

  • Java定时清理过期文件的实例代码

    项目中经常需要自动定时去清理一些过期文件,这个其实Java实现挺简单的,核心部分就2个,一个定时任务,一个递归删除文件,不过前提是你的文件放在以"2018-12-05"这样命名的文件夹下,下面直接上核心代码: 1. 递归删除文件 /** * 递归删除文件夹下所有文件 * @param file */ public static void deleteFile(File file) { if (file.isDirectory()) { //递归删除文件夹下所有文件 File[] fil

  • Java实例域初始化方法及顺序

    Java实例域初始化方式 1.构造器 public class Employee { private String name; private String gender; private int age; private double salary; public Employee() { this.salary = 1000.0; } public Employee(String name, String gender, int age, double salary) { this.name

  • 详解Java 类的加载、连接和初始化

    系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类.本节将会详细介绍类加载.连接和初始化过程中的每个细节. JVM 和类 当调用 java 命令运行某个 Java 程序时,该命令将会启动一个 Java 虚拟机进程,不管该 Java 程序有多么复杂,该程序启动了多少个线程,它们都处于该 Java 虚拟机进程里.正如前面介绍的,同一个 JVM 的所有线程.所有变量都处于同一个进程里,它们都使用该 JVM 进程的内存区.当系统出现以下几种情况时,JVM 进程将被终止. 程序运行到最

  • 详解Java的初始化与清理

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

  • 详解Java的构造方法及类的初始化

    目录 一. 利用构造方法给对象初始化 1. 构造方法的概念 2. 构造方法的特性 3. 子类构造方法 4. 避免在构造方法中调用重写的方法 二. 对象的默认初始化 三. 就地初始化对象 四. 类的初始化顺序 1. 普通类(没有继承关系) 2. 派生类( 有继承关系) 一. 利用构造方法给对象初始化 1. 构造方法的概念 构造方法(也称为构造器)是一个特殊的成员方法,其名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次. 构造方法的作用就是给对象中的成员进行初

  • 一文详解Java如何创建和销毁对象

    目录 一.介绍 二.实例构造(Instance Construction) 2.1 隐式(implicitly)构造器 2.2 无参构造器(Constructors without Arguments) 2.3 有参构造器(Constructors with Arguments) 2.4 初始化块(Initialization Blocks) 2.5 构造保障(Construction guarantee) 2.6 可见性(Visibility) 2.7 垃圾回收(Garbage collect

  • 一文详解Java过滤器拦截器实例逐步掌握

    目录 一.过滤器与拦截器相同点 二.过滤器与拦截器区别 三.过滤器与拦截器的实现 四.过滤器与拦截器相关面试题 一.过滤器与拦截器相同点 1.拦截器与过滤器都是体现了AOP的思想,对方法实现增强,都可以拦截请求方法. 2.拦截器和过滤器都可以通过Order注解设定执行顺序 二.过滤器与拦截器区别 在Java Web开发中,过滤器(Filter)和拦截器(Interceptor)都是常见的用于在请求和响应之间进行处理的组件.它们的主要区别如下: 运行位置不同:过滤器是运行在Web服务器和Servl

  • 详解java各种集合的线程安全

    线程安全 首先要明白线程的工作原理,jvm有一个main memory,而每个线程有自己的working memory,一个线程对一个variable进行操作时,都要在自己的working memory里面建立一个copy,操作完之后再写入main memory.多个线程同时操作同一个variable,就可能会出现不可预知的结果.根据上面的解释,很容易想出相应的scenario. 而用synchronized的关键是建立一个monitor,这个monitor可以是要修改的variable也可以其

  • 详解JAVA中implement和extends的区别

    详解JAVA中implement和extends的区别 extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,Java中不支持多重继承,但是可以用接口来实现,这样就要用到implements,继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了比如class A extends B implements C,D,E implements是一个类实现一个接口用的关键字,他是用来实现接口中定义的抽象方法. 还有几点需要注意: (1

  • 详解Java的堆内存与栈内存的存储机制

    堆与内存优化     今天测了一个项目的数据自动整理功能,对数据库中几万条记录及图片进行整理操作,运行接近到最后,爆出了java.lang.outOfMemoryError,java heap space方面的错误,以前写程序很少遇到这种内存上的错误,因为java有垃圾回收器机制,就一直没太关注.今天上网找了点资料,在此基础上做了个整理.  一.堆和栈 堆-用new建立,垃圾回收器负责回收 1.程序开始运行时,JVM从OS获取一些内存,部分是堆内存.堆内存通常在存储地址的底层,向上排列. 2.堆

  • 详解java中的四种代码块

    在java中用{}括起来的称为代码块,代码块可分为以下四种: 一.简介 1.普通代码块: 类中方法的方法体 2.构造代码块: 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行. 3.静态代码块: 用static{}包裹起来的代码片段,只会执行一次.静态代码块优先于构造块执行. 4.同步代码块: 使用synchronized(){}包裹起来的代码块,在多线程环境下,对共享数据的读写操作是需要互斥进行的,否则会导致数据的不一致性.同步代码块需要写在方法中. 二.静态代码块和构造

  • 详解Java面试官最爱问的volatile关键字

    本文向大家分享的主要内容是Java面试中一个常见的知识点:volatile关键字.本文详细介绍了volatile关键字的方方面面,希望大家在阅读过本文之后,能完美解决volatile关键字的相关问题.  在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性都牵扯出来,深入地话还可以考察JVM底层实现以及操作系统的相关知识. 下面我们以一次假想的面试过

随机推荐