eric-1001c

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  3 随笔 :: 45 文章 :: 12 评论 :: 0 Trackbacks

1) 惰性初始化。就是在正要使用这些对象之前,对对象进行初始化的方法。这种方式可以减少额外的负担;

 

public class Bath{
   
private String
      s1 
= "Happy",
      s2,
      s3;

   
public Bath(){
      print(
"inside Bath()");
      s2 
= "Joy";
   }


   
public String toString(){
      
//惰性初始化
      if(s3==null) s3 = "Exciting";

      
return "s1="+s1+"; s2="+s2+"; s3="+s3;
   }

}

2)在继承层次结构中,构造器的构建过程(或者说类)是从基类“向外”扩散的,所以基类在导出类构造器可以访问之前就已经完成了初始化,换句话说,调用基类的构造器必须是导出类构造器中要做的第一件事情(当然这是编译器的工作); 

3)代理。是继承和组合之间的折衷。使用代理可以拥有更多的控制力,因为可以选择只提供在成员对象中的方法的某个子集(继承就完全“暴露”了方法接口)

 1class Cleanser {
 2    private String s = "Cleanser";
 3    
 4    public void append(String a ){
 5        s += a;
 6    }

 7    public void dilute(){
 8        append("dilute()");
 9    }

10    public void apply(){
11        append("apply()");
12    }

13    public void scrub(){
14        append("scrub()");
15    }

16    public String toString(){
17        return s;
18    }

19}

20
21public class Detergent {
22    private String name;
23    private Cleanser cleanser = new Cleanser();
24    
25    public Detergent(String name){
26        this.name = name;
27    }

28        
29        //只选择暴露了Cleanser的部分方法子集
30    public void scrub(){
31        cleanser.scrub();
32    }

33    public void apply(){
34        cleanser.apply();
35    }

36    public void dilute(){
37        cleanser.dilute();
38    }

39    public String toString(){
40        return cleanser.toString();
41    }

42    /**
43     * @param args
44     */

45    public static void main(String[] args) {
46        Detergent detergent = new Detergent("detergent");
47        detergent.apply();
48        detergent.dilute();
49        System.out.println(detergent.toString());
50    }

51}

3)在清理方法中,必须注意对基类清理方法和成员对象清理方法的调用顺序,以防止某个子对象依赖于另一个子对象情形的发生:首先,执行类的所有特定的清理动作,其顺序同生成顺序相反;然后,调用基类的清理方法

4)@Override注解可以防止你不想重载(overload)时而意外进行了重载,同时也要求你使用了@Override注解后就得覆盖原来的方法
 1public class PrivateExtend1{
 2    private final void f(){
 3        System.out.println("privateExtend f()");
 4    }

 5    
 6    private  final void g(){
 7        System.out.println("privateExtend g()");
 8    }

 9}

10
11class PrivateExtend2 extends PrivateExtend1{
12//这里不注解就会错
13//    @override 
14    public final void f(){
15        System.out.println("privateExtend2 f()");
16    }

17    
18//    @Override
19    public final void g(){
20        System.out.println("privateExtend2 g()");
21    }

22}

5) 对于组合和继承的选择,一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型。如果必须向上转型,则继承是必要的,但如果不需要,则应当好好考虑自己是否需要继承。组合的好处是允许你在运行时确定对象类型,甚至调用的方法,比如 strategy pattern通过设置基类的成员变量,而传入导出类作为参数来动态改变对象类型以及方法。

6) 虽然可以通过protected关键创建一些protected域,但最好的方式还是将域保持为private;然后通过protected方法来控制类的继承者的访问权限。

7) 对于基本类型,final使数值恒定不变;而用于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而,对象其自身却是可以被修改的。

8) final和static final的区别。区别只有当数值运行时内被初始化才会显现,这是因为编译器对编译时数值一视同仁。
import java.util.Random;

public class FinalStatic {
    
private final int i1 = new Random().nextInt();
    
private static final int i2 =  new Random().nextInt();
    
    
public String toString(){
        
return ("i1: "+i1+"\t"+"i2: "+i2);
    }

    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        FinalStatic fs 
= new FinalStatic();
        System.out.println(fs.toString());
        
        FinalStatic fs2 
= new FinalStatic();
        System.out.println(fs2.toString());
    }

}

//output
i1: -1658811818    i2: 219593609
i1: 
-33942    i2: 219593609

9) Java允许“空白final”,即指被声明为final但又未给定初值的域。无论什么情况,编译器都确保空白final在使用前必须被初始化
class Poppet{
    
private int i;
    Poppet (
int i){
        
this.i = i;
    }

}

public class BlankFinal {
    
//poppet is a blank final
    private final Poppet poppet;
    
    
//blank final must be initialized before constructor
    public BlankFinal(){
        poppet
= new Poppet(5);
    }

    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        BlankFinal bf 
= new BlankFinal();
//        cann't change a final field of the object after the constructor`
//        bf.poppet = new Poppet(0);
    }

}

10)初始化及类的加载:
   1.在Beetle运行时,所发生的第一件事情就是试图访问Beetle.maini()(一个static方法)。于是加载器开始启动并找出Beetle类的编译代码(Beetle.class)。在加载过程中,编译器注意到它有基类(extends告知),于是就继续加载基类,如果基类还有基类,就继续加载下去;
   2.接下来,根基类的static初始化即会被执行,然后下一个导出类的static,以此类推。
   3.必要的类都加载完毕,对象开始创建。首先,对象中的所有基本类型都会被设为默认值,对象引用被设为null;然后,基类的成员变量会被初始化;接着基类的构造器会被调用,在基类构造器完成之后,实例变量按其次序被初始化,最后,构造器其余部分被执行
class Insect{
    
private int i = 9;
    
protected int j;
    
    Insect()
{
        System.out.println(
"i="+i+", j="+j);
        j 
= 39;
    }

    
    
private static int x1 = printInit("static Insect.x1 initialized");
    
static int printInit(String s){
        System.out.println(s);
        
return 47;
    }

}

public class Beetle extends Insect{
    
private int k = printInit("Beetle.k initialized");
    
public Beetle(){
        System.out.println(
"k=" +k);
        System.out.println(
"j=" +j);
    }

    
private static int x2 = printInit("static Beetle.x2 initialized");
    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        System.out.println(
"Beetle constructor");
        Beetle b 
= new Beetle();
    }

}

//output
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i
=9, j=0
Beetle.k initialized
k
=47
j
=39

posted on 2007-07-10 23:39 Eric-1001c 阅读(140) 评论(0)  编辑  收藏 所属分类: ThinkingInJava

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


网站导航: