当前位置:编程学习 > JAVA >>

Thinking in Java 4th chap5笔记-初始化与清理

初始化和清理
    1.this关键字
     如果有同一个类型的两个对象a和b,如何才能让这两个对象同时调用peel方法呢:
    如:
     Banana a = new Banana();
     Banana b = new Banana;
     a.peel(1);
     b.peel(2);
     如果只有一个peel方法,它如何知道是被a还是b调用呢?
     为了能用简便,面向对象的语法来编写代码,即"发送消息给对象";编译器做了一些幕后工作,他暗自把“所操作对象的引用”作为第一个参数传递给了peel->所以上述两个方法的调用变成了这样:a.peel(a,1),b.peel(b,1);这是内部的表示形式;虽然我们不能这样书写代码,并试图通过编译,不过这种写法的确能帮你了解实际发生的事情。
 如果你希望在方法内部获得对当前对象的引用,由于这个引用是编译器“偷偷”传入的,没有什么标识符可用;但为此有一个专门的关键字:this;this关键字只能在方法内部使用,表示“对调用方法的那个对象”的引用;
 当前方法的this引用会自动引用于同一类的其他方法->
 只有当需要明确指出对当前对象引用的时候,才需要使用this关键字;如需要返回当前对象的引用的时候,就常常在return语句里这样写:
 return this;
 
     注:有人执意将this放在每一个方法调用和字段引用前,认为这样“更清晰更明确”。但是千万别这么做,我们使用高级语言的原因之一就是它帮我们做一些事情。要是把this放在一些没有必要的地方,就会使读你程序的人不知所措,因为别人写的代码不会到处用this。遵循一种一致而直观的编程风格能节省时间和金钱.
     1.通过this返回对当前对象的引用,所以很容易在一条语句中对同一个对象执行多种操作;
     2.一些必要的地方才需要调用this
     3.构造器中调用构造器,this添加参数列表-产生对符合此列表的某个构造器的明确调用(除构造器之外,编译器禁止在其他任何方法调用构造器)
     4.解决参数名称和数据成员名称一致,数据成员采用this.的形式引用
     5.static方法就是没有this的方法,在static方法的内部不能调用非静态方法(这不是完全不可能,如果你传递一个对象的引用到静态方法里(静态方法可以创建其自身的对象),然后通过这个引用(和this效果相同)就可以调用非静态方法和访问非静态数据成员了。但通常要达到这样的效果,你只需写一个非静态方法即可);反过来可以;可以在没有创建对象的前提下;仅仅通过类本身调用static方法,这实际上正是static方法的主要用途;
     有些人认为static不是面向对象的,因为它的确具有全局函数的语义;使用static方法时,由于不存在this,所以不是通过“向对象发送消息”的方式来完成的;的确,要是在代码中出现了大量的static方法,就该重新考虑一下自己的设计了;然而static的概念有其实用之处,许多时候都用到它;对于它是否真的面向对象,留给理论家去讨论吧;
 
   2.终结清理和垃圾回收
     1.对象可能不被垃圾回收
     2.垃圾回收并不等于析构
     3.垃圾回收只与内存有关
      垃圾回收本身也有开销
  finalize:
       假定工作原理:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用finalize方法,并且在下一次垃圾回收动作发生时,才会真正的回收对象占用的内存;【不过要是“垃圾回收”没有发生的话,则无法释放;这个策略是恰当的,只要程序没有濒临存储空间用完的一刻;对象占用的空间总也得不到释放;因为垃圾回收也是有开销的】
      通过某种创建对象方式以外的方式为对象分配了存储空间:是由于在分配内存的时候可能使用了C语言的做法,这种做法主要发生在使用“本地”方法的情况下;本地方法是一种在Java中调用非Java代码的方式。本地方法目前只支持C/C++,但他们可以调用其他语言写的代码,所以实际上可以调用任何代码;非Java代码中,也许会调用类似C的的malloc函数系列来分配存储空间,而且除非调用了free函数,否则存储空间将得不到释放,从而造成内存泄露;当然free是C/C++的函数,所以要在finalize中用本地方法调用它;
      【记住:无论是垃圾回收还是终结,都不保证一定会发生。如果Java虚拟(jvm)并未面临内存耗尽的情况,它是不会浪费时间去执行垃圾回收以恢复内存的】
  
    3.Java堆模型
     1.一些java虚拟机的堆实现中,更像一个传送带,每分配一个新对象,就往前移动一格;对象存储空间的分配速度非常快,Java的“堆”指针只是简单的移动到尚未分配的区域;(C++的堆像一个院子,每个对象都负责管理自己的地盘,一段时间后,对象可能被销毁,但地盘必须加以重用);不过Java的堆并不完全像传送带那样工作,否则会导致频繁的内存页面调度,会显著影响性能;而垃圾回收介入之后,它工作时,一面回收空间,一面使队中的对象紧凑排列,这样“堆指针”就可以很容易移动到更靠近传送带的开始处;也就尽量避免了页面错误->通过垃圾回收器对对象重新排列,实现了一种告诉的,有无限空间可供分配的堆模型.
 
    4.垃圾回收机制:
         1.引用计数:垃圾回收器在含有全部对象的列表遍历,发现某个对象的引用计数为0,就是释放其占用的空间;不过对于对象之间的循环引用,则会出现“对象应该被回收,不过引用计数不为0”;对于垃圾回收器而言,定位这样的交叉引用的对象组所需的工作量极大;
         2.更快的模式:对任何“活”的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用;因此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有活着的对象;
         停止-复制
          标记-清扫
      两种方式程序将暂停
      自适应的,分代的,停止-复制,标记-清扫式垃圾回收器
     3.java虚拟机许多附加技术->JIT(just in time)编译器技术->
          新版JDK的Java HotSpot技术
    6.初始化
     1.方法局部变量,编译时错误保证;【当然编译器可以为局部变量赋一个默认值,不过未初始化的局部变量更有可能是程序员的疏忽,所以采用默认值反而会掩盖这种失误,因此强制程序员提供一个初始值,往往可以找到程序中的bug】
     2.类的内部,变量定义的先后顺序决定了初始化的顺序;会在任何方法(包括构造器)被调用之前得到初始化
     3.静态数据初始化,无论创建多少个对象,静态数据都只占用一份存储区域->静态初始化只有在必要时才进行->
     4.构造器可以看成是静态方法;首次创建类对象/访问类的静态方法,静态域->载入类.class->静态初始化,只在class加载的时候初始化一次->new,在堆上为该对象分配足够的存储空间->这块存储空间请0,所有基本类型被置默认值,引用null->执行所有出现于字段定义处的初始化动作->执行构造器->
     5.static{},静态子句;{},实例初始化子句;www.zzzyk.com
     6.数组初始化int[]array= {};int[] array = new int[]{}->前者只能用在数组定义处,而后者可以传参
       可变参数列表,如int...args,String...args;可变参数列表使重载过程变的复杂了->如f(Integer...args);f(Long...args)->当调用f()的时候则编译出错,因为不知道该调用哪个f方法->可以给每个方法都就加上一个非可变参数->你应该总是只在方法的一个版本上使用可变参数列表,或者压根就不是用它;
    7.enum
     枚举是类,且有自己的方法;enum的名字能够倍加清楚的表明程序意欲何为的;创建enum时,编译器会自动添加一些有用的特性,如创建toString方法,很方便的显示每个enum实例的名字;还会创建ordinal方法,表示某个特定enum常量的声明顺序;static values方法,用来按照enum常量的声明顺序,产生由这些常量构成的数组;与switch是绝佳的组合;
 直接将所得到的类型直接拿来使用,而不必过多的考虑,将enum用作另一种创建数据类型的方式;
 在枚举之前,我们需要创建一个整型常量集,但是这些常量值并不会将其自身的取值限制在这个常量集的范围内,因此显的更有风险; 更难以使用;
  当然以前这样的枚举安全机制:(个人认为还是可以满足需求的,只不过没有一些编译器添加的有用的特性,而且序列化的时候会有问题)
   public class Orie
补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,