《java编程思想》 初始化与清理
1、初始化与清理的重要性:
1、许多C程序的错误都源于程序员忘记初始化变量,特别是使用程序库时,如果不知道如何初始化库的构件更容易出错
2、当使用完一个元素时,这个元素就不会有什么影响了,所以很容易就会忘记,但是这个元素占用的资源一直存在,如果资源一直得不到释放,就会造成资源(内存)耗尽
2、构造器确保初始化:
在java中,通过提供构造器,可以确保每个对象都会得到初始化。创建对象时,如果类对象有构造器,java就会在操作对象之前自动调用相应的构造器,从而保证了初始化进行。
3、static的含义
static方法就是没有this的方法,在static方法的内部不能调用非静态方法,并且可以在没有创建任何对象的前提下,通过类本身调用static方法。
static方法中为什么不能使用this关键字?
当new 一个对象时并不是先在堆中开辟内存空间,而是先将类中的静态方法加载到方法区,然后再在堆内存中创建对象。所以说静态方法会随着类的加载而加载。当new一个对象时,该对象存在堆内存中,this关键字一般指该对象。
程序最终都在内存中执行,变量只有在内存中存在时才会被访问,类的静态成员属于类本身,在类加载的时候就会被分配内存,可以通过类名直接访问,非静态成员属于类对象,只有在类创建对象的时候才会被分配内存,然后通过类的对象进行访问。
static 方法不依赖任何对象就可以访问,因此对于静态方法来说,是没有this的,因为它不依赖于任何对象,既然都没有对象,所以就不会有this
4、清理:终结处理和垃当圾回收
finalize()方法:假定对象(并非使用new)获得了一块 "特殊"的内存区域,由于垃圾回收器只知道释放那些由new 分配的内存, 所以它不知道该如何释放这块"特殊"的内存,为了应对这种情况,java允许在类中定义一个finalize()方法。它的工作原理是: 一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
有些程序员刚开始时可能会误把finalize()方法当做C++中的析构函数(C++中销毁对象必须用到这个函数)。所以有必要明确区分一下:C++中对象一定会被销毁,java里面的对象并非总是被垃圾回收。
换句话说:
(1) 对象可能不被垃圾回收
(2) 垃圾回收并不等于 "析构"
这意味着当你不再需要某个对象之前,如果必须执行某些动作,那么得自己去做。
(3) 垃圾回收只与内存有关
使用垃圾回收器的唯一原因是为了回收程序不再使用的内存,但如果对象中含有其他对象,finalize()方法是不是就应该明确释放那些对象,不是的,无论对象是如何创建的垃圾回收器都会负责释放对象占据的内存。这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。(这段话有点拗口),但是java中一切都是对象,那特殊是指什么。
特殊情况是说由于在分配内存时可能采用了类似C语言中的做法,而不是java中的通常做法。这种情况主要发生在使用 "本地方法" 的情况下,本地方法是一种在java中调用非 java代码的方式。
通常,不能指望finalize()进行清理,必须创建其他的 "清理" 方法,并且明确调用。当对某个对象不再感兴趣,也就是说可以被清理了,这个对象应该处于某种状态,是它占用的内存可以被安全地释放。例如,要是对象代表了一个打开的文件,在对象被回收前程序员应该关闭这个文件。只要对象中存在没有被适当清理的部分,程序就存在隐晦的缺陷。finalize()可以用来最终发现这种情况。如果某次finalize()的动作使得缺陷被发现,那么就可以据此找出问题所在。
5、垃圾回收器如何工作
引用计数:引用记数是一种简单但速度很慢的垃圾回收技术,每个对象都含有一个引用计数器,当有引用连接到对象时,引用计数加1,当引用离开作用域或被设置为null 时,引用计数减1。虽然管理引用记数的开销不大,但这项开销在整个程序生命周期中将持续发生。垃圾回收器会在含有全部对象的列表上遍历,当发现某个对象的引用计数为0时,就释放其占用的空间(引用记数模式经常会在计数值为0时立即释放对象)。这种方法有个缺陷,如果对象之间存在循环引用,可能会出现 "对象应该被回收,但引用计数不为0的情况"。对垃圾回收器而言,定位这样的交互自引用的对象组所需的工作量巨大。引用记数常用来说明垃圾收集的工作方式。
在一些更快的模式中,垃圾回收器并非基于引用记数记数,其依据的思想是: 对任何 "活" 的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用。这个引用链可能会穿过数个对象层次。所以,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有 "活" 的对象,对于发现的每个引用,必须追踪它所引用的对象,然后是此对象所包含的所有引用,如此反复进行,直到 "根源于堆栈和静态存储区的引用" 所形成的网络全部被访问为止。你所访问过的对象必须都是 "活" 的。这就解决了 "交互自引用的对象组" 的问题。
在上述方式下,java虚拟机采用一种自适应的垃圾回收技术。如何处理找到的存活对象,取决于不同的java虚拟机实现。有一种做法叫 停止-----复制。显然这意味着先暂停程序的运行(所以它不属于后台回收模式),然后将所有存活的对象从当前堆复制到另一个堆,没有被复制的全部都是垃圾。当对象被复制到新堆时,它们是一个挨着一个的,所以新堆保持紧凑排列,然后就可以按前述方法简单、直接地分配新空间。当把对象从一处搬到另一处时,所有指向它的那些引用都必须修正(对象的引用从A处将指向B处)。位于堆或静态存储区的引用可以直接被修正,但可能还有其他指向这些对象的引用,它们在遍历的过程中才能被找到(可以想象成有个表格,将旧地址映射到新地址)
对于这种方法来说,效率会降低,这有两个原因,首先,得有两个堆,然后得在这两个分离的堆之间来回复制,从而得维护比实际需要多一倍的空间。第二个问题是复制。程序进入稳定状态之后,可能只会产生少量垃圾,甚至没有垃圾,尽管如此,复制式回收器仍然会将所有内存自一处复制到另一处,这很浪费。 为了避免这种情况,一些java虚拟机会进行检查:要是没有新垃圾产生,就会转换到另一种模式。这种模式成为标记-----清扫。对一般用途而言,标记---清扫方式速度相当慢,但是如果只产生少量垃圾甚至不产生垃圾时,速度就会很快了。
标记----清扫所依据的思路同样是从堆栈和静态存储区出发,遍历所有的引用,进而找出所有存活的对象。每当找到一个存活的对象,就会给对象设一个标记,这个过程中不会回收任何对象。只有全部标记工作完成的时候,清理动作才会开始。在清理过程中,没有标记的对象将被释放,不会发生任何复制动作。所以剩下的堆空间是不连续的,垃圾回收器要是希望得到连续空间的话,就得重新整理剩下的对象。
停止----复制的意思是这种垃圾回收动作不是在后台进行的,垃圾回收动作发生的同时,程序将会被暂停。当可用内存数量较低时,Sun版本的垃圾回收器会暂停运行程序,同样,标记----清扫工作也必须在程序暂停的情况下才能进行。
在java虚拟机中,内存分配以较大的 "块" 为单位,如果对象较大,会占用单独的块。严格来说,停止----复制 要求在释放旧对象之前,必须先把所有存活对象从旧堆复制到新堆,这会导致大量内存复制行为。有了 "块" 之后,垃圾回收器在回收的时候就可以往废弃的块里拷贝对象了。每个块都用相应的代数来记录它是否还存活。通常,如果块在某处被引用,其代数会增加,垃圾回收器将对上次回收动作之后新分配的块进行整理。这对处理大量短命的临时对象很有帮助。垃圾回收器会定期进行完整的清理动作----大型对象仍然不会被复制(只是其代数会增加),内含小型对象的那些块则被复制并整理。java虚拟机会进行监视,如果所有对象都很稳定,垃圾回收器的效率降低的话,就切换到标记-----清扫方式,同样,java虚拟机会跟踪标记----清扫的效果,要是堆空间出现很多碎片,就会切换到停止-----复制方式,这就是 "自适应" 技术。
6、成员初始化
对象的创建过程: 假设有个dog 类
1、即使没有显式的使用static关键字,构造器实际上也是静态方法,因此,当首次创建类型为dog的对象时(构造器可以看成静态方法),或者dog类的静态方法/静态域首次被访问时,java解释器必须查找类路径,定位 dog.class文件
2、载入dog.class (创建一个class 对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在 class 对象首次加载的时候进行一次。
3、当 new Dog() 创建对象的时候,首先将在堆上为 Dog对象分配足够的存储空间。
4、这块存储空间会被清零,就自动的将Dog对象中所有基本类型数据都设置成了默认值,引用则被设置成了 null。
5、执行所有出现于字段定义处的初始化动作
6、执行构造器
《java编程思想》 初始化与清理的更多相关文章
- Java编程思想——初始化与清理
PS:最近一直忙于项目开发..所以一直没有写博客..趁着空闲期间来一发.. 学习内容: 1.初始化 2.清理 1.初始化 虽然自己的Java基础还是比较良好的..但是在解读编程思想的时候还是发现了 ...
- 《Java编程思想》——初始化与清理(一)读书笔记
第一次写这个,这一章都用word写的,结果复制过来没图片....只能上传word文档了.以后改用markdown比较好 word文档地址:<Java编程思想>--初始化与清理(一)读书笔记
- 《 Java 编程思想》CH05 初始化与清理
< Java 编程思想>CH05 初始化与清理 用构造器确保初始化 在 Java 中,通过提供构造器,类的设计者可确保每个对象都会得到初始化.Java 会保证初始化的进行.构造器采用与类相 ...
- 《java编程思想》读书笔记(一)开篇&第五章(1)
2017 ---新篇章 今天终于找到阅读<java编程思想>这本书方法了,表示打开了一个新世界. 第一章:对象导论 内容不多但也有20页,主要是对整本书的一个概括.因为已经有过完整JAV ...
- Java编程思想(11~17)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...
- Java编程思想 (1~10)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第一章 对象导论 1.万物皆对象2.程序就是对象的集合3.每个对象都是由其它对象所构成 ...
- Java编程思想(前十章)
Java编程思想 有C++编程基础的条件下, 前10章可以快速过一下,都是基本语法,不需要花太多时间. 着重中后段的一些章节,类型信息.泛型.容器.IO.并发等. 中文翻译版 阅读地址 对于一个架构师 ...
- 《Java编程思想第四版完整中文高清版.pdf》-笔记
D.2.1 安插自己的测试代码 插入下述“显式”计时代码,对程序进行评测: long start = System.currentTimeMillis(); // 要计时的运算代码放在这儿 long ...
- 《Java编程思想》阅读笔记一
Java编程思想 这是一个通过对<Java编程思想>(Think in java)第四版进行阅读同时对java内容查漏补缺的系列.一些基础的知识不会被罗列出来,这里只会列出一些程序员经常会 ...
- Java编程思想(第4版) 中文清晰PDF完整版
Java编程思想(第4版) 中文清晰PDF完整版 [日期:2014-08-11] 来源:Linux社区 作者:Linux [字体:大 中 小] <Java编程思想>这本书赢得了全 ...
随机推荐
- Android开发 run的时候出现waiting for debugger的情况,及解决问题
出现原因:不清楚,大概推测是因为缓存没有清除干净 解决方法: 方法一. 重新启动模拟器 好像就点右上角的x符号是没有用的,因为会保存状态,在关闭之后还要点击Cold Boot Now,冷启动,才会把之 ...
- 服务器推送 SSE 了解一下?
hello~亲爱的看官老爷们大家好~过完年第一周已经结束,是时候开始制定新的工作计划了.主要负责的项目是数据可视化平台,而使用中如果服务器能有推送能力让页端得到相关通知的话,就能实现很多功能上的优化. ...
- JS 获取一段时间内的工作时长小时数
本来想是想找轮子的,但是并没有找到能用的,多数都是问题很大,所以就自己写了一个 需求说明 支持自选时间段,即开始时间与结束时间根据用户的上班及下班时间判定返回小时数 技术栈 moment.js 思考过 ...
- web页面上展示图片时,图片不显示,报错:ERR_CONTENT_LENGTH_MISMATCH
问题描述 前端页面加载css,和js文件的时候,经常出现ERR_CONTENT_LENGTH_MISMATCH的报错情况. 查找问题 在单独打开hearder中css,js的网络地址是能打开的 ...
- 【Java必修课】判断String是否包含子串的四种方法及性能对比
1 简介 判断一个字符串是否包含某个特定子串是常见的场景,比如判断一篇文章是否包含敏感词汇.判断日志是否有ERROR信息等.本文将介绍四种方法并进行性能测试. 2 四种方法 2.1 JDK原生方法St ...
- 一起了解 .Net Foundation 项目 No.17
.Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. Peachpie Comp ...
- unittest测试框架详解
单元测试的定义 1. 什么是单元测试? 单元测试是指,对软件中的最小可测试单元在与程序其他部分相隔离的情况下进行检查和验证的工作,这里的最小可测试单元通常是指函数或者类,一般是开发来做的,按照测试 ...
- win10安装docker 和 splash
参考链接1:https://www.cnblogs.com/321lxl/p/9536616.html 参考链接2:https://blog.csdn.net/qq_18831501/article/ ...
- D2T1服务器需求——毒?瘤题(并不是
这题我第一眼居然差点错了\(OTZ\) 然后写了线段树,还写挂了-- 写好了\(query\)操作,发现似乎不需要区间查询,然后又删掉-- 看着这熟悉的操作,似乎在哪里见过-- 然后我莫名其妙把一个\ ...
- php7连接mysql8
最近因为剁手买了mac所以在mac上搭建lnmp环境. 刚好看到mysql从5.7跳到8,性能据说快上一倍,果断尝鲜! lnmp基本都弄好了,但是到用php连接Mysql这一步出了岔子. 出错原因: ...