《疯狂java--突破程序员基本功的16课》读书笔记

该书讲述了大部分程序员容易忽视的细节性问题,如果有条件建议详细阅读。

2.2.3 调用被子类重写的方法(34)
如果父类构造器调用了被子类重写的方法,且通过子类构造器来创建子类对象,调用了这个父类的构造器,就会导致子类的重写方法在子类构造器的所有代码之前被执行,从而导致子类的重写方法访问不到子类的实例变量值的情形。

2.2.2 访问子类对象的实例变量(32)
如下情况可以出现父类访问子类的情况。

  
  
  
  
  1. view plaincopy to clipboardprint?  
  2. class Base     
  3. {     
  4.     int i=2;     
  5.     public Base()     
  6.     {     
  7.         this.display();     
  8.     }     
  9.     public void display()     
  10.     {     
  11.         System.out.println(i);     
  12.     }     
  13. }     
  14. class Derived extends Base     
  15. {     
  16.     int i=22;     
  17.     public Derived()     
  18.     {     
  19.         i=222;     
  20.     }     
  21.     public void display()     
  22.     {     
  23.         System.out.println(i);     
  24.     }     
  25. }     
  26. public class Test     
  27. {     
  28.     public static void main(String[] args)     
  29.     {     
  30.         new Derived();     
  31.     }     
  32. }   

这个程序的输出结果是多少?
答案如下:
如果子类与父类有同样的成员变量,则子类的隐藏掉父类的,内存中还是会有这2个变量的。
构造器负责对java对象实例变量执行初始化也就是赋值,在此之前该对象所占内存已经被分配下来,但都是默认的空值。(0、false、null)
Derived类,可以重写成

  
  
  
  
  1. view plaincopy to clipboardprint?  
  2. class Derived extends Base     
  3. {     
  4.     int i=0;     
  5.     public Derived()     
  6.     {     
  7.         super();     
  8.         i=2;     
  9.         i=222;     
  10.     }     
  11.     public void display()     
  12.     {     
  13.         System.out.println(i);     
  14.     }     
  15. }   

由此可以更清楚地看到Derived的对象是如何被创建出来的了!
super里调用了子类的display()方法,该方法执行的时候i的值还未被赋值,也就是说还是0,所以打印结果是0;

2.3.1 继承成员变量和继承成员方法的区别(36)
如下情况的输出个是多少呢?

  
  
  
  
  1. view plaincopy to clipboardprint?  
  2. public static void main(String[] args)     
  3. {     
  4.     Base b = new Base();        //2     
  5.     Derived d = new Derived();  //0     
  6.     System.out.println(d.i);    //222     
  7.     d.display();                //222     
  8.            
  9.     Base bd = new Derived();    //0     
  10.     System.out.println(bd.i);   //2     
  11.     bd.display();               //222     
  12.          
  13.     Base b2d = d;     
  14.     System.out.println(b2d.i);  //2     
  15.     b2d.display();              //222     
  16. }   

由上可以看出即便是引用到的子类对象,但成员变量依然同引用的类型。
如果在子类重写了父类的方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。对于实例变量则不存在这样的现象,即使子类中定义了与父类完全同名的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量。
因为继承成员变量和继承方法之间存在这样的差别,所以对于一个引用类型的变量而言,当通过该变量访问它所引用的对象的实例变量时,该实例变量的值取决于声明该变量时类型;当通过该变量来调用它所引用的对象的方法时,该方法行为取决于它所实际引用的对象的类型。


--------------------------------------------------------------------------------

2.4.2 执行“宏替换”的变量(49)

  
  
  
  
  1. view plaincopy to clipboardprint?  
  2. public static void main(String[] args)     
  3. {     
  4.     String s1 = "疯狂JAVA";     
  5.     String s2 = "疯狂" + "JAVA";     
  6.     System.out.println( s1 == s2 );  //true     
  7.     String str1 = "疯狂";     
  8.     String str2 = "JAVA";     
  9.     String s3 = str1 + str2;     
  10.     System.out.println( s1 == s3 );  //false     
  11.          
  12.     final String fs1 = "疯狂";     
  13.     final String fs2 = "JAVA";     
  14.     String s4 = fs1 + fs2;     
  15.     System.out.println( s1 == s4 );  //true     
  16. }   

 由于编译器可以在编译阶段就确定s2的值为 "疯狂JAVA" ,所以系统会让s2直接指向字符串池中缓存中的 "疯狂JAVA" 字符串,所以 s1 == s2 为 true ;
str1 ,str2为2个String变量,编译器在编译阶段不能确定s3的值,所以s3不会指向字符串池中缓存中的  "疯狂JAVA" 。所以 s1 == s3 为 false ;
fs1,fs2,被 final 修饰,编译器可以在编译阶段确定s4的值,所以 s1 == s4 为 true ;


--------------------------------------------------------------------------------

4.4.3 尽早释放无用对象的引用(124)

  
  
  
  
  1. view plaincopy to clipboardprint?  
  2. public void info()     
  3. {     
  4.     Object obj = new Object();     
  5.     Sysout.out.println(obj.toString());//对obj的操作     
  6.     obj = null//如果没有此句,Object对象会在info()方法执行后才被回收     
  7.     //执行耗时,耗内存操作,需要obj提前被回收     
  8. }   

4.4.4. 尽量少用静态变量(124)
某个对象被 static 变量所引用,那么垃圾回收机制通常是不会回收这个对象所占的内存。直到程序运行结束。

你可能感兴趣的:(移动开发,读书笔记,休闲,疯狂Java,突破程序员基本功的16课)