如何速成java_极*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速成是看不懂的了.....

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值