Java编程思想 第五章读书笔记

来源:互联网 发布:js 拖拽事件 编辑:程序博客网 时间:2024/06/02 00:39

1.用构造器确保初始化 : 如果没有构造器,那么就会有一个构建方法,这个方法需要我们在使用对象之前去创造对象,使得对象初始化,如何命名这个方法呢?它可能会和成员方法的名字相同了,如何让编译器轻松的找到这个方法。java采用的方法是采用类名作为构造方法的名字。当我们new 一个对象的时候,会为对象分配空间,调用类的构造器,初始化对象数据。默认的构造器就是无参构造器。构造器的使用,有利于我们减少错误,使得代码更容易阅读。构造器是一种特殊的方法,他没有返回值也没有把这个方法定义为 void。 new 表达式确实返回了对新对象的引用, 然而构造器并没有返回任何类型。

2.方法重载: 为什么要有方法重载? 我们在描述一个方法名的时候,想实现的效果是一样的含义比如print  它表达了同样的行为方式,如果没有重载我们会怎么描述print printInt printString printLong等等,这样很冗余。又例如我们的构造方法,如果没有方法重载,那么我们就不能有不同形式的构造对象的形式。因为方法名要独一无二。有了方法重载有什么好处?他们的名字相同,他们表达相同的行为,不同的是他们的参数列表,这样我们可以把所有类型的输出都叫print 把所有形式的构造方法都定义为类名。

对于涉及到基础类型的重载,我们要注意 基本数据类型可以向上转型。

我们通过参数列表进行区分不同的方法而不是采用返回值来区分不同方法的原因是当我们需要执行一个方法,只是单纯的调用这个方法,不知道返回值类型的时候我们就不知道调用的是哪个方法了。

3.默认构造器: 如果我们没有创建构造器,编译器会为我们构建默认的无参构造器。当然如果我们已经创建了,编译器就不会构建默认构造器。

4.this 关键字 ? 为什么要有这个关键字?在方法里 如果我们已经有了int  a  对象也有一个int a 如果直接用a 则我们用的是这个方法里的a。如果没有this这个关键字,我们没办法在方法里拿到对象的属性。this关键字只能在方法内部使用,表达对“调用方法的那个对象”的引用。this的用法就像我们的对象引用。但是如果是方法内调用同一个类的另外一个方法就不需要了。当我们需要在方法返回值里返回对象的引用时,可以返回this。 我们在构造器中调用构造器,有时可能想在构造器调用别的构造器,以免重复代码,可以通过this.调用构造器。this可以调用构造器,但是不能调用两个。必须将构造器置于最起始的位置。

全面理解static static就是没有this的方法,在static方法内无法调用非静态的方法(非static的方法),反过来是可以的。可以在未创建任何对象的情况下,仅仅通过类本身就可以调用static方法,这就是static方法的主要用途。static方法可以访问 其他static 的方法和属性。通过static修饰的方法和属性,好似是类的全局属性和方法。

5.清理 终结处理和垃圾回收  一旦垃圾回收器准备好释放某个对象会调用 finalize方法,并且在下一次垃圾回收动作发生时才会去真正的回收内存。我们可以重写finalize方法做一些重要的清理工作。(可以跳过剩下部分关于垃圾回收的介绍)。我对垃圾回收的一些理解,我们不知道每个厂家对Java回收器会有什么样的调整,但是我们知道对象是否可以被回收是和它是否有引用有关系的,因此我们可以养成在我们明确不再使用对象的时候,把对象的引用制空,以便虚拟机回收。

1.对象可能不被垃圾回收

2.垃圾回收不等于析构

3.垃圾回收只与内存有关

如果我们要做清理,必须自己去创建一个清理的普通方法。只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。如果程序结束,并且垃圾回收你创建的任何对象的空间,则随着程序退出,那些资源也会全部交给操作系统。因为垃圾回收是有开销的,如果不使用它就会被清理掉。

finalize() 的用途何在? 

垃圾回收的目的是回收程序不再使用的内存,对于与垃圾回收有关的行为来说,一定与内存及其回收有关。我们在一个类中如果包含其他对象的引用,在finalize是否需要去明确释放那部分对象呢?no 无论对象是如何创建的,垃圾回收都会负责释放对象占据的内存。为什么要有finalize方法,既然它不能不会立即通知释放。之所以要有finalize方法是因为在分配内存的时候可能采用了类似C语音的做法,而非Java的通常做法。这种情况主要发生在使用“” 本地方法“  ”的情况下,本地方法 是一种Java中调用的非 java方法的方式。在非Java代码中也许会调用C 的 malloc() 函数系来分配存储空间,而且除非调用了free() 函数,否则存储空间得不到释放,从而造成了内存泄露。因为Free()是本地方法,因此需要在finalize 调用本地方法。 finalize不适合频繁调用,也不是普通的清理工作。

Java必须通过new 创建对象,Java中没有C++中的delete方法(调用析构函数)因为垃圾回收器会帮助我们释放存储空间,或者说因为有了垃圾回收机制,没有了 析构函数然而垃圾回收机制不能完全的替代析构函数(绝对不能直接调用finalize方法)如果希望进行除了释放存储空间以外的工作,还是得明确的调用Java方法,这就等于使用了析构函数,但是没有它方便。

我们怎么使用finalize? 我们把 finalize作为终结条件的验证,finalize只会存在于程序员很难会用到的一些晦涩的用法里了。当对某个对象没有兴趣了,这个对象应该处于该状态,使得它占用的内存得到释放。finalize可以用来最终发现这种情况——尽管它并不是总被调用,如果某次finalize的动作使得缺陷被发现,那么就可以据此找出问题所在。

垃圾回收原理:引用计数是简单但是速度很慢的垃圾回收技术。每个对象都会有一个引用计数器,当有引用连接至对象时,引用计数加1。当引用离开作用域时或者引用置为null时,引用计数减一。尽管管理引用计数的开销不大,这项开销在程序的整个生命周期持续发生,垃圾回收器会把所有对象都遍历一边,发现引用计数为0时就释放其占用空间。这个方法的缺点是如果对象之间存在循环引用,可能会出现对象应该被回收,但是计数不为0的情况。对于垃圾收集器来说,定位这样的交互自引用的对象组需要很大的工作量。因此引用计数器方式未被应用于Java虚拟机

另外一个垃圾回收思想是:对任何活的对象,一定能追溯其存活在堆栈或静态存储区域的引用。这个引用链条可能要穿过多个对象层次。换个思维,从堆栈和静态存储区域就可以找到所有活的对象,然后此对象包含的所有引用,如此反复,直到“根源于堆栈或者是静态存储空间的引用”所形成形成的网络全部被访问为止,你所访问过的对象都是活的。这就解决了交互自引用的对象组。

在这种方式下,虚拟机将采用自适应的垃圾回收技术。有一种如何处理活的对象,有一种做法叫做停止-复制(先把程序暂停,然后把所有存活的对象从当前堆中复制到另一个堆),没有被复制的都是垃圾,清理掉。复制到新堆,他们是有序的得意让新堆保持紧凑排列,然后就可以按上述方法简单直接的分配空间了。

当把对象从一处搬到另一处所有指向它的引用都需要修正,位于堆和静态存储区域的引用可以直接被修正,但是可能还有指向这些对象的引用,它们在遍历过程中才能被找到。对于这种复制式回收器而言,效率低,维护更多的空间。在运行期间,及时没有垃圾,也会进行复制,浪费资源。为了避免这个现象的产生,Java会进行检查,要是没有新的垃圾,就会换到另外一种工作模式(自适应)。这种模式为标记-清理    标记-清理的方式清理速度缓慢但是当你知道只会产生小量垃圾或者不会产生垃圾,它就很快了。

标记-清理 思路也是从静态存储区域和堆出发,遍历所有引用,进而找出所有活的对象,为每个活的对象标记,这个过程不会回收任何对象,只有全部标记工作完成之后才会开始标记,在清理过程中,没有标记的对象将被释放,不会产生任何复制工作。剩下的空间是不连续的,垃圾回收器如果想获得连续的空间就要重新整理剩下的对象。

停止-复制 的意思不适合后台进行,相反会阻塞程序,许多文献将垃圾回收视为低优先级的后台进程。同样的,标记-清理也需要在程序暂停的时候进行。

6.成员初始化 :对于对象的变量Java会在对象创建的时候初始化,而局部变量,Java通过编译器提示你需要在使用的时候初始化。我们可以在定义类成员变量的地方为成员变量赋值,我们不仅可以给基本数据类型赋值,也可以给其他对象赋值(new 对象),或者通过成员方法赋值。我们要注意的是,初始化是有先后顺序的,我们不能调提使用还没有初始化好的对象,否则会造成错误。

7.构造器初始化 为什么要使用构造器初始化?这样我们可以更加方便更加灵活的初始化对象,然而变量是先进行类的初始赋值然后才是构造器赋值。

例如成员变量 i 在构造器进行赋值 那么它赋值顺序是:编译器给i默认赋值为 0  然后构造器赋值为1;

类的内部,变量定义的顺序,决定了初始化的先后顺序。即使变量定义散布在方法定义之间,它们仍会在任何方法调用前得到初始化。

举个例子, 我们编写类的时候,在几排成员变量的定义中间插入成员方法的定义。在对象初始化时,按照变量定义的顺序先进行初始化。

无论创建多少对象,静态数据部分只占用了一份存储区域。静态成员会在非静态成员之前初始化,静态基本类型的初始化同非静态基本类型。

静态代码块,用于执行静态变量的初始化的代码块(只会调用一次为静态成员变量赋值)。只会在首次生成这个类的对象时引用,或者从未创建过这个类的对象,首次通过类名调用这个静态变量。 例子 static int i;  static {  i=7; }

非静态代码块,也是用于初始化,与静态代码块不同的是 它没有static 。这个语法对于支持匿名内部类的初始化是必须的,它使得我们可以保证哪个显示构造器某些操作都会发生。我们会发现这个方法会在显示构造器执行前执行。












0 0
原创粉丝点击