Java基础: 静态与动态代码块

来源:互联网 发布:快剪软件 编辑:程序博客网 时间:2024/05/22 13:39

定义:在定义属性的位置上,在任何方法之外,定义一个代码块  

种类:分为两类即动态代码块、静态代码块

<1> 动态初始代码块:在初始化属性之前调用初始化代码块  {……}
<2> 静态初始代码块:在类加载时运行    static{……}  只被运行一次,往往用作一个类的准备工作

示例代码:

[java] view plaincopyprint?
  1. package mark.zhang;  
  2. public class Linux {  
  3.     /** 
  4.      * 动态代码块 
  5.      */  
  6.     {  
  7.         System.out.println("--动态初始化代码块--");  
  8.     }  
  9.       
  10.     /** 
  11.      * 静态代码块 
  12.      */  
  13.     static {  
  14.         System.out.println("--静态初始化代码块--");  
  15.     }  
  16.       
  17.     /** 
  18.      * 测试 
  19.      *  
  20.      * @param args 
  21.      */  
  22.     public static void main(String[] args) {  
  23.         Linux linux = new Linux();  
  24.     }  
  25. }  
 

执行结果:

[java] view plaincopyprint?
  1. --静态初始化代码块--  
  2. --动态初始化代码块--  
 

从结果看出,创建Linux类的实例时加载这个类,从而代码块执行,只是静态代码块先于动态代码块之前执行。那么,我们思考两个问题,类何时被加载,代码块、构造方法以及成员变量之间的执行顺序是谁先谁后??汗,别急,往下看。

先说一说类加载时机吧!!

(1)new 一个对象的时候,加载

(2)没有创建对象,访问类中静态方法(final和非final的均可以)和静态属性(不可以被final修饰,final修饰的静态属性是在常量池里),加载

(3)声明一个类的引用,不加载

(4)创建子类,先加载父类,再加载子类

(5)父类中的公开静态方法,子类继承,使用子类的类名调用此方法,加载父类

 注意,这里需要满足两个条件:

 <a> 子类不可以重写该静态方法,其实父类的静态方法子类是不可以重写只可以继承的。即使重写也要加上static关键字。那么也就说明父类的静态方法是不可以被子类重写的,子类重写的这个静态方法称之为子类自己的静态方法(只不过和父类的该静态方法重名罢了!!)

 <b>  main方法不可以在子类中,看例子代码,如下:

 

[java] view plaincopyprint?
  1. package mark.zhang;  
  2. public class Linux {  
  3.     /** 
  4.      * 动态代码块 
  5.      */  
  6.     {  
  7.         System.out.println("--父类Linux--动态初始化代码块--");  
  8.     }  
  9.       
  10.     /** 
  11.      * 静态代码块 
  12.      */  
  13.     static {  
  14.         System.out.println("--父类Linux--静态初始化代码块--");  
  15.     }  
  16.       
  17.     static void get() {  
  18.         System.out.println("--父类Linux--get()");  
  19.     }  
  20. }  
  21. class Ubuntu extends Linux {  
  22.       
  23.     /** 
  24.      * 动态代码块 
  25.      */  
  26.     {  
  27.         System.out.println("--子类Linux--动态初始化代码块--");  
  28.     }  
  29.       
  30.     /** 
  31.      * 静态代码块 
  32.      */  
  33.     static {  
  34.         System.out.println("--子类ubuntu静态初始化代码块--");  
  35.     }  
  36. }  
  37. class Test {  
  38.     /** 
  39.      * 测试 
  40.      *  
  41.      * @param args 
  42.      */  
  43.     public static void main(String[] args) {  
  44.         Ubuntu.get();  
  45.     }  
  46. }  

在主函数中运行以下代码:

[java] view plaincopyprint?
  1. //加载了父类之后,虚拟机已经知道m()方法的调用了,就不会再加载子类,延迟加载  
  2. Ubuntu.get();     

运行结果:

[java] view plaincopyprint?
  1. --父类Linux--静态初始化代码块--  
  2. --父类Linux--get()  

(6)没有创建对象,访问类中静态常量(能计算出结果的常量,在编译的时候会用计算出来的结果替换表达式),不加载 

(7)没有创建对象,访问类中静态常量(不确定的值),加载   

关于(6)(7),举两个个小例子吧??!!!

[java] view plaincopyprint?
  1. package my.test;  
  2. public class FinalTest {  
  3.     //  编译时常量,编译器在编译时会将所有用到该变量的地方替换成相应的字面值  
  4.     public static final int a = 4+4;  
  5.       
  6.     static {  
  7.         System.out.println("--static code--");  
  8.     }  
  9. }  
  10. class Test {  
  11.     public static void main(String[] args) {  
  12.         System.out.println("FinalTest.a= " + FinalTest.a);  
  13.     }  
  14. }  
 

该例子中没有执行静态代码块,正如(6)所说。

运行结果:

[java] view plaincopyprint?
  1. FinalTest.a= 8  
 

再看一个例子,来说明(7)的正确性!!!

[java] view plaincopyprint?
  1. package my.test;  
  2. public class FinalTest {  
  3.     // 运行时常量,在运行的时候才能确定  
  4.     public static final int a = 4 + Math.abs(1);  
  5.       
  6.     static {  
  7.         System.out.println("--static code--");  
  8.     }  
  9. }  
  10. class Test {  
  11.     public static void main(String[] args) {  
  12.         System.out.println("FinalTest.a= " + FinalTest.a);  
  13.     }  
  14. }  
 

运行结果,执行静态代码块内容。

[java] view plaincopyprint?
  1. --static code--  
  2. FinalTest.a= 5  
 

ok,上面说的都是关于类的加载时机问题,接着说说代码块、构造方法以及成员变量之间的执行顺序的问题。要想说明白这个问题,需要从两个方面说,一个是单纯的一个类,另一个就是一个类与另一个类的继承。

<1> 单纯的一个类

[java] view plaincopyprint?
  1. package mark.zhang;  
  2. public class Linux {  
  3.     // 静态成员变量  
  4.     public static String name = "Linux OS";  
  5.     // 一般变量  
  6.     public int size = 2;  
  7.       
  8.     public Linux() {  
  9.         System.out.println("--父类Linux--构造方法--");  
  10.     }  
  11.       
  12.     /** 
  13.      * 动态代码块 
  14.      */  
  15.     {  
  16.         System.out.println("--父类Linux--动态初始化代码块--");  
  17.     }  
  18.       
  19.     /** 
  20.      * 静态代码块 
  21.      */  
  22.     static {  
  23.         System.out.println("--父类Linux--静态初始化代码块--");  
  24.     }  
  25.       
  26. }  
 

测试一下,呵呵!!

[java] view plaincopyprint?
  1. class Test {  
  2.     /** 
  3.      * 测试 
  4.      *  
  5.      * @param args 
  6.      */  
  7.     public static void main(String[] args) {  
  8.         new Linux();  
  9.     }  
  10. }  
 

测试结果,如下:

[java] view plaincopyprint?
  1. --父类Linux--静态初始化代码块--  
  2. --父类Linux--动态初始化代码块--  
  3. --父类Linux--构造方法--  
 

<2> 具有继承关系的两个类

[java] view plaincopyprint?
  1. package mark.zhang;  
  2. public class Linux {  
  3.     // 静态成员变量  
  4.     public static String name = "Linux OS";  
  5.     // 一般变量  
  6.     public int size = 2;  
  7.       
  8.     public Linux() {  
  9.         System.out.println("--父类Linux--构造方法--");  
  10.     }  
  11.       
  12.     /** 
  13.      * 动态代码块 
  14.      */  
  15.     {  
  16.         System.out.println("--父类Linux--动态初始化代码块--");  
  17.     }  
  18.       
  19.     /** 
  20.      * 静态代码块 
  21.      */  
  22.     static {  
  23.         System.out.println("--父类Linux--静态初始化代码块--");  
  24.     }  
  25.       
  26. }  
  27. class Ubuntu extends Linux {  
  28.       
  29.     public Ubuntu() {  
  30.         System.out.println("--子类Ubuntu--构造方法--");  
  31.     }  
  32.       
  33.     /** 
  34.      * 动态代码块 
  35.      */  
  36.     {  
  37.         System.out.println("--子类Ubuntu--动态初始化代码块--");  
  38.     }  
  39.       
  40.     /** 
  41.      * 静态代码块 
  42.      */  
  43.     static {  
  44.         System.out.println("--子类ubuntu静态初始化代码块--");  
  45.     }  
  46. }  
  47. class Test {  
  48.     /** 
  49.      * 测试 
  50.      *  
  51.      * @param args 
  52.      */  
  53.     public static void main(String[] args) {  
  54.         new Ubuntu();  
  55.     }  
  56. }  
 

执行结果,如下:

[java] view plaincopyprint?
  1. --父类Linux--静态初始化代码块--  
  2. --子类ubuntu静态初始化代码块--  
  3. --父类Linux--动态初始化代码块--  
  4. --父类Linux--构造方法--  
  5. --子类Ubuntu--动态初始化代码块--  
  6. --子类Ubuntu--构造方法--  
 

至于,代码块与成员变量之间谁先谁后,其实是与它们在类中声明顺序有关的。现在以一个小例子说明问题:

[java] view plaincopyprint?
  1. package mark.zhang;  
  2. public class Linux {//静态与非静态成员变量与静态代码块、非静态代码块的执行顺序与其声明顺序有关  
  3.       
  4.     RedHat rh1 = new RedHat("非静态成员变量rh1");  
  5.     static RedHat rh11 = new RedHat("静态成员变量rh11");  
  6.       
  7.     public Linux() {  
  8.         System.out.println("--父类Linux--构造方法--");  
  9.     }  
  10.       
  11.     /** 
  12.      * 动态代码块 
  13.      */  
  14.     {  
  15.         System.out.println("--父类Linux--动态初始化代码块--");  
  16.     }  
  17.       
  18.     /** 
  19.      * 静态代码块 
  20.      */  
  21.     static {  
  22.         System.out.println("--父类Linux--静态初始化代码块--");  
  23.     }  
  24.       
  25.     RedHat rh2 = new RedHat("非静态成员变量rh2");  
  26.     static RedHat rh22 = new RedHat("静态成员变量rh22");  
  27. }  
  28. class RedHat {  
  29.     static int times = 1;  
  30.     public RedHat(String info) {  
  31.         System.out.println(info + ", the order " + (times++));  
  32.     }  
  33. }  
 

测试:

[java] view plaincopyprint?
  1. class Test {  
  2.     /** 
  3.      * 测试 
  4.      *  
  5.      * @param args 
  6.      */  
  7.     public static void main(String[] args) {  
  8.         new Linux();  
  9.     }  
  10. }  
 

运行结果:

[java] view plaincopyprint?
  1. 静态成员变量rh11, the order 1  
  2. --父类Linux--静态初始化代码块--  
  3. 静态成员变量rh22, the order 2  
  4. 非静态成员变量rh1, the order 3  
  5. --父类Linux--动态初始化代码块--  
  6. 非静态成员变量rh2, the order 4  
  7. --父类Linux--构造方法-- 
0 0
原创粉丝点击