这篇文章总结来自于两篇博文:
http://blog.csdn.net/clam_clam/article/details/6689998
http://hbiao68.iteye.com/blog/1676081
首先有三个概念需要了解:
一.静态初始化:是指执行静态初始化块里面的内容。
二.实例初始化:是指执行实例初始化块里面的内容。
三.构造方法:一个名称跟类的名称一样的方法,特殊在于不带返回值。
我们先来看一段程序结果:
- package com;
- class Book{
- public static int booksum=0;//静态变量
- static{//这是静态初始化块
- print();
- System.out.println("this is static block");
- }
- {//实例初始化块
- System.out.println("初始化块:"+booksum);
- }
- public Book(){//构造方法
- System.out.println("this is Book's constructor~");
- booksum+=1;
- }
- public static void print(){//静态方法
- System.out.println("this is static method~");
- }
- public static void main(String []args){
- //Book book=new Book();
- }
- }
执行结果:
this is static method~
this is static block
如果把
- public static void main(String []args){
- //Book book=new Book();
- }
this is static method~
this is static block
初始化块:0
this is Book's constructor~
总结:
仅从代码执行的角度来探讨Java加载类、创建对象的过程,并没有深入到JVM的机制中去。
1.一个对象第一次被创建时,先要加载该对象所属的类,即对应的.class文件,当然如果类已经加载,再次创建该类的对象时,就不再需要重新加载类了。而一个类加载的时候,有三个部分需要加载,一个是静态变量,再然后是静态方法,然后是静态初始化块。 (见到第一次执行结果就知道了,由于没有创建实例所以初始化块不执行)
2.然后开始创建该类的实例了,当然如果静态方法跟静态初始化对象中有对象的创建时,就继续加载该对象的类,当然已经加载了该对象的类的话就不需要再次加 载了。那么对象实例的创建过程是什么呢?首先是成员变量的引入,然后是实例初始化块,之后才是构造方法,构造方法执行完成之后才算把这个对象给创建出来了。
在这个过程中,真正可以编写执行代码的地方有三个,静态初始化、实例初始化以及构造方法。从以上的分析中我们可以看到,这三个代码块的执行顺序是先类的静态初始化,再实例初始化,最后执行构造方法。也就是说,静态初始化是属于类加载的过程,所以它只执行一次,而实例初始化是每个对象创建时都会执行一次,而构造方法跟实例初始化其实也差不多,不过它在实例初始化之后执行,而且构造方法可以重载多个,执行哪个构造方法是根据你的选择来的。
可以把main () 函数加一条语句看看:
- public static void main(String []args){
- Book book=new Book();
- Book book1=new Book();
- }
this is static method~
this is static block
初始化块:0
this is Book's constructor~
初始化块:1
this is Book's constructor~
这说明实例初始化是每个对象创建时都会执行的。
Java编译器会收集所有的类变量初始化语句和类型的静态初始化器,将这些放到一个特殊的方法中:clinit
实际上,static块的执行发生在“初始化”的阶段。初始化阶段,jvm主要完成对静态变量的初始化,静态块执行等工作
- public class A {
- static {
- System.out.println("static is a");
- }
- {
- System.out.println("class A block");
- }
- public A(){
- System.out.println("this is a");
- }
- }
- public class B extends A{
- static{
- System.out.println("static is b");
- }
- {
- System.out.println("class B block");
- }
- public B(){
- System.out.println("this is b");
- }
- }
- package hb.mm;
- public class Test {
- /**
- * 考察点
- * 当一个类被主动使用时,Java虚拟就会对其初始化,如下六种情况为主动使用:
- 1.当创建某个类的新实例时(如通过new或者反射,克隆,反序列化等)
- 2.当调用某个类的静态方法时
- 3.当使用某个类或接口的静态字段时
- 4.当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的
- 方法时
- 5.当初始化某个子类时
- 6.当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类)
- Java编译器会收集所有的类变量初始化语句和类型的静态初始化器,将这些放到一个特殊的方法中:
- clinit实际上,static块的执行发生在“初始化”的阶段。初始化阶段,jvm主要完成对静态变量的初
- 始化,静态块执行等工作
- */
- public static void main(String[] args) {
- // 当子类被初始化的时候父类也要跟着初始化
- A ab = new B();
- System.out.println("---------------------");
- new B();
- }
- }
static is a
static is b
class A block
this is a
class B block
this is b
---------------------
class A block
this is a
class B block
this is b
--------------------------------------------------------------------------------------------------------------------------------------------------
java静态变量存放区静态的意思:只有一份!不存在拷贝!
虚拟机内存分为四个区:stack segment,heap segment,data segment,code segment;
stack 区存放函数参数和局部变量;
heap 区存放对象;
data 区存放static 的变量或者字符串常量;
code 区存放类中的方法;
所以,静态变量是存放在data区的
静态变量属于类的属性。至于他放在那里?有人说的是静态区。我不知道到底有没有这个翻译。但是 深入jvm里是是翻译为方法区的。虚拟机的体系结构:堆,方法区,本地方法栈,pc寄存器。而方法区保存的就是一个类的模板,堆是放类的实例的。栈是一般来用来函数计算的。随便找本计算机底层的书都知道了。栈里的数据,函数执行完就不会存储了。这就是为什么局部变量每一次都是一样的。就算给他加一后,下次执行函数的时候还是原来的样子。
static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
全局变量和静态变量的区别:
全局变量在整个工程文件内都有效;静态全局变量只在定义它的文件内有效;静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数返回后失效。全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。