读Java编程思想随笔の初始化与清理

  初始化和清理正式涉及安全的两个问题。

  如果用户不知道如何初始化库的构件(或者用户必须初始化的其他东西),更是如此。清理也是一个特殊问题,当使用完一个元素时,它对你也就不会有什么影响,所以很容易把它忘记。这样一来,这个元素占用的资源就会一直得不到释放,结果是资源用尽。

  用构造器确保初始化

  在Java中,通过提供构造器,类的设计者可确保每个对象都会得到初始化。创建对象时,如果其类具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造器,从而保证了初始化的进行。

  现在创建对象时:new Rock();

  将会为对象分配存储空间,并调用相应构造器。这就确保了在你能操作对象之前,它已经被恰当地初始化了。

  不接受任何参数的构造器叫做默认构造器,Java文档中的术语是无参构造器,但是默认构造器在Java出现之前已经使用许多年了,所以我仍旧倾向于使用它。但是和其他方法一样,构造器也能带有形式参数,以便指定如何创建对象。

  默认构造器

 1 public class NoSynthesis {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         Bird2 b1 = new Bird2(1);
 6         Bird2 b2 = new Bird2(2.8);
 7         Bird2 b1 = new Bird2();//no default
 8     }    
 9 }
10 class Bird2{
11     Bird2 (int i) {}
12     Bird2 (double d) {}
13 }

  要是你这样写:

  new Bird2()

  编译器就会报错:没有找到匹配的构造器。这就好比,要是你没有提供任何构造器,编译器会认为“你需要一个构造器,让我给你制造一个吧”;但假如你已经写了一个构造器,编译器则会认为“啊,你已经写了一个构造器,所以你知道你在做什么;你是可以省略了默认构造器”。

  this关键字

 1 public class Leaf {
 2     int i = 0;
 3     Leaf increment (){
 4         i++;
 5         return this;
 6     }
 7     void print(){
 8         System.out.println("i="+i);
 9     }
10     public static void main(String[] args) {
11         // TODO Auto-generated method stub
12         Leaf x = new Leaf();
13         x.increment().increment().increment().print();
14     }
15 //    i=3
16 
17 }

  由于increment()通过this关键字返回了对当前对象的引用,所以很容易在一条语句里对同一个对象执行多次操作。

  this关键字对于当前对象传递给其他方法也很有用。

 1 public class PassingThis {
 2     public static void main(String[] args) {
 3         // TODO Auto-generated method stub
 4         new Person().eat(new Apple());
 5     }
 6 }
 7 class Person {
 8     public void eat(Apple apple){
 9         Apple peeled = apple.getPeeled();
10         System.out.println("Yummy");
11     }
12 }
13 class Peeler{
14     static Apple peel (Apple apple){
15         return apple;
16     }
17 }
18 class Apple {
19     Apple getPeeled(){
20         return Peeler.peel(this);
21     }
22 }
23 //Yummy

  Apple需要调用Peeler.peel()方法,他是一个外部的工具方法,将执行由于某种原因而必须放在apple外部的操作(也许是因为该外部方法要应用于许多不同的类,而你却不想重复这些代码)。为了将自身传递给外部方法,apple必须使用this关键字。

  static

  static方法是没有this的方法。在static方法的内部不能调用非静态方法,反过来倒是可以。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static的用途,它很像全局方法。Java中禁止使用全局方法,但你在类中置于static方法就可以访问其他static方法和static域。

  清理 终结处理和垃圾回收

  Java有垃圾回收器负责回收无用对象占据的内存资源。但也有特殊情况,假定你的对象并非使用new获得一块特殊的内存区域,由于垃圾回收器只知道回收那些使用new分配的内存,所以它不知道该如何释放对象这块“特殊”的内存。为了应对这种情况,Java允许在类中定义一个名为finalize()方法。它的工作原理“假定”是这样的,一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用finalize(),并且下一次垃圾回收动作发生时,才能真正释放内存。

  垃圾回收本身就有内存开销

  垃圾回收期如何工作

  垃圾回收器对于提高对象的创建速度,却具有明显的效果。听起来很奇怪,存储空间的释放竟然会影响存储空间的分配,但这确实是某些Java虚拟机的工作方式。

  当它工作时,将一面回收空间,一面使堆中的对象紧凑排列,这样堆指针就可以很容易移动到更靠近传送带的开始处,也就尽量避免了页面错误。通过垃圾回收器对对象的重新排列,实现了一种高速的,有无限空间可供分配的堆模型。

  静态数据的初始化

  无论创建多少个对象,静态数据都只占用一份存储区域。static关键字不能用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值;如果它是一个对象的引用,那么它的默认初始化值就是null。

 1 public class StaticInitialization {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         System.out.println("create new Cupboard () in main");
 6         new Cupboard ();
 7         System.out.println("create new Cupboard () in main");
 8         new Cupboard ();
 9         table.f2(1);
10         cupboard.f3(1);
11         
12     }
13     static Table table = new Table ();
14     static Cupboard cupboard = new Cupboard ();
15 
16 }
17 class Bowl {
18     Bowl (int marker) {
19         System.out.println("Bowl("+marker+")");
20     }
21     void f1 (int marker) {
22         System.out.println("f1("+marker+")");
23     }
24 }
25 class Table {
26     static Bowl bowl1 = new Bowl(1);
27     Table () {
28         System.out.println("Table ()");
29         bowl2.f1(1);
30     }
31     void f2 (int marker) {
32         System.out.println("f2("+marker+")");
33     }
34     static Bowl bowl2 = new Bowl(2);
35 }
36 class Cupboard {
37     Bowl bowl3 = new Bowl(3);
38     static Bowl bowl4 = new Bowl(4);
39     Cupboard () {
40         System.out.println("Cupboard ()");
41         bowl4.f1(2);
42     }
43     void f3 (int marker) {
44         System.out.println("f3("+marker+")");
45     }
46     static Bowl bowl5 = new Bowl(5);
47 }
48 
49 
50 /*
51  * Bowl(1)
52  * Bowl(2)
53  * Table ()
54  * f1(1)
55  * Bowl(4)
56  * Bowl(5)
57  * Bowl(3)
58  * Cupboard ()
59  * f1(2)
60  * create new Cupboard () in main                
61  * Bowl(3)
62  * Cupboard ()
63  * f1(2)
64  * create new Cupboard () in main
65  * Bowl(3)
66  * Cupboard ()
67  * f1(2)
68  * f2(1)
69  * f3(1)
70  * */
71 /*1、普通变量初始化优先于静态变量初始化*/
72 /*2、静态变量初始化只会被执行一次*/
View Code

  显式的静态初始化

 1 public class ExplicitStatic {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         System.out.println("inside main()");
 6         Cups.cup1.f(99);
 7     }
 8 
 9 }
10 class Cup {
11     Cup(int marker){
12         System.out.println("Cup("+marker+")");
13     }
14     void f (int marker){
15         System.out.println("f("+marker+")");
16     }
17 }
18 class Cups {
19     static Cup cup1;
20     static Cup cup2;
21     static {
22         cup1 = new Cup(1);
23         cup2 = new Cup(2);
24     }
25     Cups(){
26         System.out.println("Cups()");
27     }
28 }
29 //inside main()
30 //Cup(1)
31 //Cup(2)
32 //f(99)

  数组初始化

  int [] a1 = {1,2,3,4,5}

  那么,为什么还要在没有数组的时候定义一个数组引用呢?

  int [] a2

  在Java中可以将一个数组赋值给另一个数组,所以可以这样:

  a2 = a1

  其实真正做的只是复制了一个引用

 1 public class ArraysOfPrimitives {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         int [] a1 = {1,2,3,4,5};
 6         int [] a2 ;
 7         a2 = a1;
 8         for (int i = 0; i < a2.length; i++) {
 9             a2 [i] +=1;
10         }
11         for (int i = 0; i < a1.length; i++) {
12             System.out.println("a1["+i+"]="+a1[i]);
13         }
14     }
15     /**
16      * a1[0]=2
17      * a1[1]=3
18      * a1[2]=4
19      * a1[3]=5
20      * a1[4]=6
21      */
22 }

  可变参数列表

  Object... args

  String... args

  Character... args

  int... args

  ...

  ...

  可传多个参数,也可不传参数

 1 public class OptionalTrailingArguments {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         //f(1,"one");
 6         //f(1,"one","two");
 7         //f(0);
 8         g(0);
 9         g(1,"one");
10         f(2,"one","two");
11     }
12     static void f (int required,String... trailing) {
13         System.out.println("required"+required+"\t");
14         for (int i = 0; i < trailing.length; i++) {
15             System.out.println(trailing[i]+ "");
16         }
17         System.out.println();
18     }
19     static void g (Object... trailing){
20         for (int i = 0; i < trailing.length; i++) {
21             System.out.println(trailing[i]+ "");
22         }
23     }
24 
25 }
26 //0
27 //1
28 //one
29 //required2    
30 //one
31 //two

  枚举类型

 1 package com.hhl.initialization.enums;
 2 public enum Spiciness {
 3     NOT,MILD,MEDIUM,HOT,FLAMING
 4 }
 5 
 6 package com.hhl.initialization.enums;
 7 public class SimpleEnumUse {
 8 
 9     public static void main(String[] args) {
10         // TODO Auto-generated method stub
11         Spiciness s = Spiciness.HOT;
12         System.out.println(s);//HOT
13     }
14 
15 }

  ordinal()方法可返回某个特定enum常量的声明顺序,以及static values()方法返回由这些常量值构成的数组:

 1 public class EnumOrder {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         for (Spiciness s : Spiciness.values()) {
 6             System.out.println(s+",ordinal:"+s.ordinal());
 7         }
 8     }
 9 //    NOT,ordinal:0
10 //    MILD,ordinal:1
11 //    MEDIUM,ordinal:2
12 //    HOT,ordinal:3
13 //    FLAMING,ordinal:4
14 
15 }

  enum有一个特别使用的特性,即它可以和switch语句有完美的配合:

public class Burrito {
    Spiciness s;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Burrito plain = new Burrito(Spiciness.HOT),
                greenChile = new Burrito(Spiciness.MEDIUM),
                jalapeno = new Burrito(Spiciness.HOT);
        plain.describe ();
        greenChile.describe ();
        jalapeno.describe ();
    }
    public Burrito (Spiciness s) {
        this.s = s;
    }
    void describe () {
        System.out.print("this is burrito");
        switch (s) {
        case NOT: System.out.println(" not spicy at all");break;
        case MILD: 
        case MEDIUM: System.out.println(" a little hot");break;
        case HOT: 
        case FLAMING:
        default: System.out.println(" maybe too hot");
        }
    }
//    this is burrito maybe too hot
//    this is burrito a little hot
//    this is burrito maybe too hot

}

 

posted @ 2015-10-28 08:28  有志竟成  阅读(139)  评论(0)    收藏  举报