I want to fly higher
programming Explorer
posts - 114,comments - 263,trackbacks - 0

初始化和清理
    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{},静态子句;{},实例初始化子句;
     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 Oriented
  {
   private int value;
   //两个安全非final枚举
   public static final Oriented ORI = new Oriented(1);
   public static final Oriented OR2  = new Oriendted(2);

   //私有构造函数
   private Oriented(int v)
   {
    value = v;
   }
  }
    8.垃圾回收器的确增加了运行时的开销,而且Java解释器从来就很慢;随着时间推移,java在性能方面已经取得了长足的进步,不过速度问题仍然是它涉及某些编程领域的障碍.    
    9.部分源码    

package com.book.chap5.initAndDestroy;
/**
 *
 *Finalize用法,验证终结条件
 *<p>本例的终结条件是:所有的book对象在垃圾回收都应该checkin;main方法中,有一本书没有被签入,被finalize方法发现,输出消息</p>
 *
 *@author landon
 *@since JDK1.6
 *@version 1.0 2012-4-12
 *
 
*/

public class FinalizeUsage
{
    
public static void main(Stringargs)
    
{
        Book novel = new Book(true);
        novel.checkIn();
        
        
new Book(true);
        
        
//强制进行终结动作[当然也可以通过重复的执行程序,假设程序将要分配大量的存储空间,而导致垃圾回收动作的进行,最终也能找到错误的Book]
        System.gc();
    }

}


class Book
{
    
private boolean checkOut;
    
    
public Book(boolean checkOut)
    
{
        
this.checkOut = checkOut;
    }

    
    
/**
     * 检入,书籍只有检入后才可以被垃圾回收
     
*/

    
public void checkIn()
    
{
        checkOut = false;
    }

    
    @Override
    
protected void finalize()
    
{
        
if(checkOut)
        
{
            System.out.println("Error: has book checked out");
            
try
            
{
                
//调用父类的finalize方法
                super.finalize();
            }
 
            
catch (Throwable e)
            
{
                e.printStackTrace();
            }

        }

    }

}

        

package com.book.chap5.initAndDestroy;
/**
 *
 *枚举enum的初步用法
 *
 *@author landon
 *@since JDK1.6
 *@version 1.0 2012-4-12
 *
 
*/

public class SimpleEnum
{
    
public static void main(Stringargs)
    
{
        Spiciness howHot = Spiciness.MEDIUM;
        
//打印枚举,toString方法已实现
        System.out.println(howHot);
        
        
//ordinal按照声明顺序从0开始
        for(Spiciness spiciness : Spiciness.values())
        
{
            System.out.println(spiciness + " ordinal:" + spiciness.ordinal());
        }

        
        testSwitchEnum(Spiciness.MILD);
        testSwitchEnum(Spiciness.HOT);
        testSwitchEnum(Spiciness.FLAMING);
    }

    
    
//测试enum和switch的组合
    public static void testSwitchEnum(Spiciness spiciness)
    
{
        
switch(spiciness)
        
{
            
//注意case必须是NOT必须是无限制的枚举名称[spiciness的类型已经确定是枚举Spiciness,没有必要特意加上Spiciness.NOT,画蛇添足],而不是Spiciness.NOT,否则编译报错The qualified case label Spiciness.NOT must be replaced with the unqualified enum constant NOT
            case NOT:
                System.out.println("not");
                
break;
            
case MILD:
                System.out.println("mild");
                
break;
            
case MEDIUM:
                System.out.println("medium");
                
break;
            
case HOT:
            
case FLAMING:
            
default:
                System.out.println("too hot");
        }

    }

}


//枚举声明
enum Spiciness
{
    
//常量,大写
    NOT,MILD,MEDIUM,HOT,FLAMING
}

 

package com.book.chap5.initAndDestroy;
/**
 *
 *可变参数
 *<p>可变参数列表可以使用任何类型的参数,包括基本类型</p>
 *
 *@author landon
 *@since JDK1.6
 *@version 1.0 2012-4-12
 *
 
*/

public class VarArgs
{
    
public static void main(Stringargs)
    
{
        printArgsClass(1);
        
        
//输出class [I getClass,产生对象的类
        System.out.println(new int[0].getClass());
        
        f(1,'a');
        
//The method f(float, Character[]) is ambig        uous for the type VarArgs
//f('a','b');
    }

    
    
public static void printArgsClass(intargs)
    
{
        System.out.println(args.getClass());
    }

    
    
//重载的时候,使用可变参数列表一定要谨慎;非常有可能出现模棱两可的调用->从而导致编译报错
    public static void f(float f,Characterargs)
    
{
        System.out.println(
"first method");
    }

    
    
public static void f(Characterargs)
    
{
        System.out.println(
"second method");
    }

}


posted on 2013-01-08 17:04 landon 阅读(1677) 评论(0)  编辑  收藏 所属分类: ProgramBook

只有注册用户登录后才能发表评论。


网站导航: