极*Java速成教程 - (2)
Java语言基础
Java的一切都是以对象为基础,对象是生是死的生命周期由虚拟机管理,但是在创生和消亡阶段,需要我们去管理这个类怎么生,怎么死。我们也以此为契机,慢慢接触Java的诸多细节和具体实现。
对象的构造
初始化
Java中的对象需要被初始化,如果不进行指定的初始化,就会赋予一个默认值或者是导致错误和异常。
Java中类内部属性的初始化是顺序从前到后的,并且先进行成员变量的初始化,再进行构造器的初始化。
对象属性的初始化可以通过在类中定义一个初始值(这个值可以是直接赋予的,也可以是方法的返回值),也可以通过对象构造器进行初始化,那就可以“定制”出具有某种默认属性的对象。
单个对象的初始化可以通过直接赋值实现,多个对象形成的数组可以使用new实现随时随地的初始化,也可以在声明数组引用时使用{}
将一系列的对象包起来,然后使用=
直接对数组进行初始化赋值:
Integer[] A={new Integer(1),2,3}
Integer[] A= new Integer[3]
静态成员变量会比非静态成员变量先初始化,它会在类的第一个对象初始化时进行初始化,它的值与普通成员变量的初始化方法相同,且只会初始化一次。可以在花括号前使用static关键字,将花括号内所有成员标记为静态。
构造器
正如世界上一切生物的诞生都要遵循一定的自然规律,Java对象的诞生也要遵循一定的规则,那就是通过构造器构造对象。Java对象的创建和初始化时绑定在一起的,就像孕妇腹中胎儿所占的空间和胎儿的发育是息息相关的。通过一个构造器,一个新的Java对象被赋予属性,Java语言默认为每个类赋予了一个与其同名的默认构造器,这个构造器没有参数,没有代码,是一个空的方法。构造器也没有返回值。这里带来了几个陌生的术语,这也是我们需要研究和关心的。
方法
Java的方法,是一段动态的,表示对象行为的代码,可以执行一些功能。一个Java方法,有以下几个部分:
- 方法名:表明一个方法的名字,名字的合法性需要遵循Java要求,也就是只能有字母,数字,下划线和$符号,数字不能作为开头,不能和关键字相同,大小写敏感
- 参数列表:方法是一个行为,行为要对一些对象进行处理,参数就是告诉这个方法要对这些对象进行处理。Java对参数的类型和顺序都敏感,孙悟空和孙悟净不是一个人,孙行者和行者孙也不是同一个人,这在方法的重载中起到了重要作用。
- 方法体:方法体就是方法具体的行为描述,可长可短,但是应该条理清晰不要太长。
- 返回值:方法对对象进行处理后,有时候要返回一个结果,返回值的类型是要注明的。
方法名、参数列表和方法所在类名一起标识了方法的唯一性,有一个不同就能区分方法的不同。
方法重载
Java提供了默认构造器,这个构造器和类名同名,然后没有参数也没有返回值,但是按照Java模拟真实世界的想法来思考,会发现有一些不妥:生下来的婴儿并非真的白纸一片什么属性都没有。那怎么给一个“初生”的类赋予属性呢,仅靠无法提供更多输入的默认构造器是不够的。因此,Java提供了方法重载的功能,也就是对于同名的一系列方法,可以根据参数列表的不同加以区分,以实现同样功能下的细微区分。对于构造器来说,Java默认提供了一个全空白的构造器,开发者可以根据实际的需求,写出一个同样名称但是不同参数列表的方法,实现不同的初始化目的,比如可以重载一个体重参数和一个身高参数,写出4个不同的构造方法,就可以使用同名的构造器方法初始出一个信息全空白的婴儿,初始一个出生5斤的婴儿,初始一个出生30厘米的婴儿,初始一个出生6斤32厘米的婴儿,这就实现了在对象的初始化时赋予对象属性的功能。
在方法重载时还有几点:
- 基本类型重载时,会优先完全匹配,但如果向参数列表中较大的参数提供了较小的实际对象,Java会自动将较小的参数对象自动提升为较大的对象,比如将byte对象提升为int对象,然后传到方法中。如果将一个较大的对象传递到较小的参数中,如果不进行类型转换和截取,是会报错的,这和Java运算时的向上扩大思想是一致的。
- 在同名方法重载时,靠参数列表进行区分,参数列表的顺序和类型都可以作为区分,但是返回值不能作为重载的区分方法。如果两个函数名称和参数列表都一致但是返回值不同,这会给开发者和编译器都带来困扰。
- Java会提供默认构造器,但如果开发者自己定义了构造器,那默认构造器就会被屏蔽,“消失”掉。
可变参数列表
一般来说,一个方法的参数是固定数量的,但是我们有时候也会出现传递一个数组作为参数的情况,这个时候不妨拓展一下思路:可以把参数整体作为一个数组么?实际上这是可行的,也就是可变参数列表。通过将某一种类型的多个参数放到数组中,然后将数组的引用传递到方法中,就可以将不定数量的参数传递到方法中,这一过程被Java所简化支持。
void f(Object... args){
}
“我”怎么称呼我自己
对于一个人来说,别人叫你什么可以通过取一个称号实现,对于Java来说,就是“引用”。对于一个人自称,现实世界中可以用“鄙人”,“我”之类的称呼,对于Java来说,这个功能是怎么实现的呢?那就是this。开发者可以使用this来访问当前对象的属性和方法,this就指代了它所在的类本身。这会给传递当前对象本身和调用当前对象的方法带来便利。
对于一个对象来说,它可以用this来自称,但是对于一个类来说,就不能用this来指代具体的自己了,这时,static方法起到了同样的作用,也就是说static是一个类的自称。因此,static静态方法不能轻松地“放下身段”调用对象的非静态方法,静态方法要从类的层次去设计和运行。
垃圾的回收
一个对象是有生命周期的,当需要用的时候我们可以创建一个对象,但当使用完毕时,我们就可以将它抛弃,它就成了一个“垃圾”。但是正如现实中的垃圾要分类回收处理,Java中的垃圾对象也要回收处理,否则会占用内存中的空间。关于垃圾回收有以下几个特点:
- 对象可能不被垃圾回收。Java对象的生命周期管理是虚拟机掌握的,是程序员难以控制的,程序员无法决定一个垃圾什么时候会被从内存中丢出去。
- 在类里定义
finalize()
方法可以在Java垃圾回收时进行一些操作。垃圾回收器会在准备释放内存空间时调用finalize()
方法,但是在下一次垃圾回收动作发生时,才会真正回收对象所占用的内存。 - 有垃圾回收不等于可以趁垃圾回收时“安排后事”。虽然可以定义一个
finalize()
方法在对象生命周期的末端做一些处理,但当一个对象不被使用时,开发者应该按照自己的需要做一些收尾处理,因为Java虚拟机的垃圾回收未必会发生也难以预料何时会发生。 - 因此,
finalize()
方法应该只在特殊的时候使用,那这个特殊时机是什么时候呢?那就是在Java使用JNI等手段调用本地方法时。Java垃圾回收器会回收所有的对象,而Java万物皆对象,因此Java都能被回收,不能回收需要程序员处理的,也就是这种不是Java的东西所占用的内存了。 finalize()
除了4中说到的使用方法,还有一种特殊的使用方法,就是设定一个终结条件,在finalize()
方法中对这个条件进行判断,可以对一些程序的缺陷进行预警和发现。比如程序在逻辑上占用了一个资源,就可以在finalize()
方法中判断资源是否释放,如果没有释放就进行处理。
垃圾回收器
垃圾回收器是干什么的
Java时一种一切皆对象的语言,对象的创建和删除都被Java虚拟机所控制,对象创建在堆上,而垃圾处理器对于堆空间的管理至关重要,垃圾处理器对对象所占用的空间进行有序排列,在堆开始处留出大块空间放置新的对象,井井有条的堆空间起到了加速对象创建的作用,对于Java性能的影响至关重大。
垃圾回收的思路
垃圾处理器最为简单的思路就是引用计数,也就是一个对象,统计有多少个引用指向它,当引用超出作用域时计数-1,当引用计数归零时,就意味着这个对象已经没人用了,那这个对象就可以作为垃圾被回收了,但是这个算法会有一些问题:对象之间可能互相引用,然后带来类似于死循环的问题,所以这个算法并没有真正用于垃圾回收。
实际上Java虚拟机垃圾回收的做法是基于一种“按图索骥”的思想:先在堆栈和静态储存区寻找所有的引用,然后根据引用找到这些对象,然后寻找这些对象的引用,逐层深入,最终寻找到所有“活着的”引用的所有相关对象网络,不在网络中的对象就成了垃圾,被垃圾回收器回收掉
垃圾回收器实际算法
停止-复制
这不是一种后台回收方法。在执行一段时间后,垃圾回收器会暂停程序的运行,然后将所有存活的对象复制到另一个堆或者另一大块内存空间中,在复制时将内存空间重新紧密排布并修改所有引用的内存地址。很显然,这种方法首先需要暂停程序运行,第二需要另一大块内存空间,第三复制过程需要耗费大量的时间,第四可能在运行的这段时间内并没有产生很多的垃圾,让对象在内存中整体搬一次家是意义很小的,因此是一种费时费空间的垃圾回收算法。
标记-清扫
这种方法会遍历堆栈和静态储存区所有引用进而寻找出所有存活的对象,在标记过程中不会回收任何对象,在标记完成时释放没有被标记的空间。因此这个方法会留下不连续的空间,如果需要获得连续空间那还需要对内存进行整理。
自适应
Java虚拟机中内存的分配是以块为单位的,大型的对象被放置在单独的块中,多个小的临时的短命的对象被放在一个块中,这为Java的垃圾回收提供了一些便利和好处,垃圾回收器可以在回收的时候就开始往已经废弃的块中复制数据。
Java在每个块上放置一个代数(一代人的代)记录块是否存活,如果一个块被引用,那么代数就会增加。
垃圾回收器定期进行一次完整的清理。大的对象不会被复制,含有小型对象的块会被复制和整理。
垃圾回收器会对对象进行监视,如果对象生命周期稳定,垃圾回收器效率降低,就会切换到“标记-清扫”方法进行清理,如果堆空间出现大量的碎片,就会切换到“停止-复制”方法进行清理。
在我的理解中,垃圾回收器实现了在块内针对小对象实现“停止-复制”,在块间实现“标记-清扫”,然后在监视过程中动态切换算法,以提高效率。
感觉....好像应该在学过Java以后再来看这一系列的文章.....似乎从0速成是看不懂的了.....
极*Java速成教程 - (2)的更多相关文章
- 极*Java速成教程 - (1)
序言 众所周知,程序员需要快速学习新知识,所以就有了<21天精通C++>和<MySQL-从删库到跑路>这样的书籍,Java作为更"高级"的语言也不应该落后, ...
- 极*Java速成教程 - (8)
Java高级特性 注解 注解可以在代码之外添加更多的信息,更加完整地描述程序,帮助编译器进行工作,或者实现某些特定的Java代码之外的功能. 注解可以简化某些重复的流程,自动化那些过程. 注解的使用 ...
- 极*Java速成教程 - (7)
Java高级特性 数组 在Java中,数组是一串连续的,不可改变长度的,对象被固定的,类型固定的连续空间.数组中的随机访问非常迅速,但为了速度放弃了灵活性.而效率也是数组最大的优点. 在使用泛型的容器 ...
- 极*Java速成教程 - (6)
Java高级特性 String String是Java中的字符串类型,字符串类型在内存中是一个不可变的对象.如果要对字符串对象进行修改,如果是较少的修改可以使用+运算符,Java会自动进行优化,但如果 ...
- 极*Java速成教程 - (5)
Java语言基础 容器 这个世界是有序的,将Java对象零散地放到内存中是不符合世界常理的,特别是有一大组相似的甚至不知道有多少数据的时候.把Java对象装进盒子里可以有序收纳,这个盒子就叫容器. 初 ...
- 极*Java速成教程 - (4)
Java语言基础 多态 多态是面向对象的一大重要特性,如果说封装是隐藏一个类怎么做,继承是确定一系列的类做什么,那多态就是通过手段去分离做什么和怎么做. 向上转型与收窄 在开发者将一类事物封装成类以后 ...
- 极*Java速成教程 - (3)
Java语言基础 访问权限控制 Java是一个面向对象的语言,当你不是它所设计的要面向的对象时,它就不会给你看你不该看到的东西,也就是"访问权限控制". 亲疏有别,才能权限控制 包 ...
- 极·Java速成教程 - (1)
序言 众所周知,程序员需要快速学习新知识,所以就有了<21天精通C++>和<MySQL-从删库到跑路>这样的书籍,Java作为更"高级"的语言也不应该落后, ...
- Java IO教程
1 Java IO 教程 2 Java IO 概述 3 Java IO: 文件 4 Java IO: 管道 5 Java IO: 网络 6 Java IO: 字节和字符数组 7 Java IO: S ...
随机推荐
- 【hiho1044】状压dp1
题目大意:给定一个长度为 N 的序列,每个位置有一个权值,现选出一些点,满足相邻的 M 个点中至多有 Q 个点被选择,求选出点权的最大值是多少. 题解:若没有相邻的限制,这道题类似于子集和问题,即:背 ...
- 从输入URL到页面加载到底发生了什么
很多初学网络或者前端的初学者大多会有这样一个疑问:从输入URL到页面加载完成到底发生了什么?总的来说,这个过程分为下面几个步骤:1.DNS解析2.与服务器建立连接3.服务器处理并返回http报文4.浏 ...
- CTF Jarvisoj Web(session.upload_progress.name php 上传进度)
Jarvisoj Web 题目地址:http://web.jarvisoj.com:32784/index.php <?php //A webshell is wait for you ini_ ...
- 用C语音编写python的扩展模块,也就是python调c库
用C语音编写python的扩展模块,也就是python调c库 1.用C语言扩展Python的功能: http://www.ibm.com/developerworks/cn/linux/l-pyt ...
- c++ printf和cout的性能
今天做了一道编程题,仔细检查了算法并没有错误,但是结果显示时间超时,但仍有80%的案例通过了,很奇怪. 通过将cin换成scanf,cout换成printf结果AC,实验发现二者性能差了很多,在输出1 ...
- eclipse设置maven web项目打包
如图:eclipse下的maven web项目,打包部署到本地tomcat时,需要关注的2个方面: 1. src/main/webapp目录下的文件,打包到/ 根路径下 2. 添加maven 依赖,打 ...
- linux运维、架构之路-Kubernetes集群部署
一.kubernetes介绍 Kubernetes简称K8s,它是一个全新的基于容器技术的分布式架构领先方案.Kubernetes(k8s)是Google开源的容器集群管理系统(谷歌内部 ...
- PHP入门培训教程 php动态网页怎么转换成html
当动态网页遇上搜索引擎 虽然动态网页相比于静态页面拥有许多优势,但它在搜索引擎的检索上却碰了个大钉子.无论任何一家网站,尤其是那些以营销为目的的企业网站,没有谁会希望自己的网页无法被搜索引擎检索 ...
- 「树形结构 / 树形DP」总结
Codeforces 686 D. Kay and Snowflake 要求$O(n)$求出以每个节点为根的重心. 考虑对于一个根节点$u$,其重心一定在[各个子树的重心到$u$]这条链上.这样就能够 ...
- 查看windosw服务器型号和序列号
查看服务器型号 wmic csproduct get name 查看序列号 wmic bios get serialnumber 查看内存 wmic memorychip list brief === ...