java中的静态代码块、构造代码块、构造函数执行顺序

来源:互联网 发布:udid 分发平台源码 编辑:程序博客网 时间:2024/05/16 07:50


静态代码块、构造代码块、构造函数执行顺序转载

一、什么时候会加载类?
  使用到类中的内容时加载:有三种情况
    1.创建对象:new StaticCode();
    2.使用类中的静态成员:StaticCode.num=9;  StaticCode.show();
    3.在命令行中运行:java StaticCodeDemo

二、类所有内容加载顺序和内存中的存放位置:
 利用语句进行分析。
  1.Person p=new Person("zhangsan",20);
   该句话所做的事情:
   1.在栈内存中,开辟main函数的空间,建立main函数的变量 p。
   2.加载类文件:因为new要用到Person.class,所以要先从硬盘中找到Person.class类文件,并加载到内存中。
    加载类文件时,除了非静态成员变量(对象的特有属性)不会被加载,其它的都会被加载。
    记住:加载,是将类文件中的一行行内容存放到了内存当中,并不会执行任何语句。---->加载时期,即使有输出语句也不会执行。
     静态成员变量(类变量)  ----->方法区的静态部分
     静态方法                ----->方法区的静态部分
     非静态方法(包括构造函数) ----->方法区的非静态部分
     静态代码块     ----->方法区的静态部分
     构造代码块     ----->方法区的静态部分
     
     注意:在Person.class文件加载时,静态方法和非静态方法都会加载到方法区中,只不过要调用到非静态方法时需要先实例化一个对象,对象才能调用非静态方法。如果让类中所有的非静态方法都随着对象的实例化而建立一次,那么会大量消耗内存资源,
     所以才会让所有对象共享这些非静态方法,然后用this关键字指向调用非静态方法的对象。   
   3.执行类中的静态代码块:如果有的话,对Person.class类进行初始化。
   4.开辟空间:在堆内存中开辟空间,分配内存地址。
   5.默认初始化:在堆内存中建立 对象的特有属性,并进行默认初始化。
   6.显示初始化:对属性进行显示初始化。
   7.构造代码块:执行类中的构造代码块,对对象进行构造代码块初始化。
   8.构造函数初始化:对对象进行对应的构造函数初始化。
   9.将内存地址赋值给栈内存中的变量p。
  2.p.setName("lisi");
   1.在栈内存中开辟setName方法的空间,里面有:对象的引用this,临时变量name
   2.将p的值赋值给this,this就指向了堆中调用该方法的对象。
   3.将"lisi" 赋值给临时变量name。
   4.将临时变量的值赋值给this的name。
  3.Person.showCountry(); 
   1.在栈内存中,开辟showCountry()方法的空间,里面有:类名的引用Person。
   2.Person指向方法区中Person类的静态方法区的地址。
   3.调用静态方法区中的country,并输出。
    注意:要想使用类中的成员,必须调用。通过什么调用?有:类名、this、super

三、静态代码块、构造代码块和构造函数的区别
  静态代码块:用于给类初始化,类加载时就会被加载执行,只加载一次。
  构造代码块:用于给对象初始化的。只要建立对象该部分就会被执行,且优先于构造函数。
  构造函数:  给对应对象初始化的,建立对象时,选择相应的构造函数初始化对象。  
   创建对象时,三者被加载执行顺序:静态代码块--->构造代码块--->构造函数
  
//利用代码进行测试 例题:06--06:StaticCodeDemo.java
class Person
{
 private String name;
 private int age=0;
 private static String country="cn"; 
 Person(String name,int age)
 {
  this.name=name;
  this.age=age; 
 }
 static
 {
  System.out.println("静态代码块被执行"); 
 }
 { System.out.println(name+"..."+age); }
 public void setName(String name)
 {
  this.name=name; 
 }
 public void speak()
 {
  System.out.println(this.name+"..."+this.age); 
 }
 public static void showCountry()
 {
  System.out.println("country="+country); 
 }
}
class StaticDemo
{
 static
 {
  System.out.println("StaticDemo 静态代码块1"); 
 }
 public static void main(String[] args)
 {
  Person p=new Person("zhangsan",100);
  p.setName("lisi");
  p.speak();
  Person.showCountry(); 
 }
 static
 {
  System.out.println("StaticDemo 静态代码块2"); 
 
}
输出结果:
   StaticDemo 静态代码块1
   StaticDemo 静态代码块2
   静态代码块被执行
   null...0    //构造代码块
   lisi...100  //speak()
   country=cn  //showCountry()
  




  1. 几大原则 
  2.          一、静态成员变量(Static) 
  3.           1、静态成员变量为类变量,所有对象共享同一内存空间 
  4.           2、静态成员变量的声明和定义仅在首次加载类时执行一次 
  5.           3、首次加载类时首先对所有静态成员变量根据类型默认赋初值,然后再对有右值的附右值 
  6.          二、静态初始块 
  7.           1、静态初始化块仅在首次加载类时执行一次 
  8.          ······多个静态成员变量与静态始化快参照出现顺序先后执行······ 
  9.          三、动态成员变量 
  10.           1、动态成员变量定义在每次实例化对象时在构造函数之前执行 
  11.          四、动态初始化块 
  12.           1、动态初始化块在每次实例化对象时在构造函数之前执行 
  13.          ······多个动态成员变量与动态初始化块参照出现顺序先后执行······ 
  14.          总结:总的来说,在不涉及继承的前提下,当首次加载类时,按照如下顺序执行 
  15.           1、按照出现顺序先后执行静态成员变量定义与静态初始化块 
  16.           2、按照出现顺序先后执行动态成员变量定义与动态初始化块 
  17.           3、执行构造函数 
  18.           再次实例化对象时只执行第2、3步即可 
  19.           
  20.          ············成员变量与定义与初始化块先于构造函数执行········· 
  21.          五、当涉及到继承时,按照如下顺序执行 
  22.           1、执行父类的静态成员变量定义与静态初始化块,执行子类的静态成员变量定义与静态初始化块 
  23.           2、执行父类的非静态成员变量定义与动态初始化块,执行父类构造方法 
  24.           3、执行子类的非静态成员变量定义与动态初始化块,执行子类构造方法 
  25.          另:父类构造方法中用到的方法如果已被子类重写,那么在构造子类对象时在调用父类构造函数中使用子类重写的方法 




原因如下:
        构造代码块中的代码也是在构造方法中执行的。在编译时的编译器看来会默认将构造代码块中的代码移动到构造方法中,并且移动到构造方法内容的前面。
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestCode {
     
    public TestCode() {
        System.out.println("构造方法");
    }
     
    {
        System.out.println("代码块");
    }
     
    public static void main(String[] args) {
        new TestCode();
    }
}

相当于
Java code
?
1
2
3
4
5
6
7
8
9
10
11
public class TestCode {
     
    public TestCode() {
        System.out.println("代码块");
        System.out.println("构造方法");
    }
     
    public static void main(String[] args) {
        new TestCode();
    }
}

你记住了这一点,以后在做很多关于用构造方法或代码块赋值的问题就明白了。


0 0
原创粉丝点击