Java 的 static 关键字总结

static 可以修饰:
  1. 静态变量(静态域)
  2. 静态代码块
  3. 静态方法
  4. 静态类

1、静态变量
  • 无论创建多少个对象,该类的所有实例都共享同一个static变量,静态数据都只占用一份存储区域。也就是说在类加载的时候分配一块存储空间,所有此类的对象都可以操作此块存储空间。
  • static关键字不能作用于局部变量,因此它只能作用于域(字段)
  • 如果一个域是静态的基本类型,且也没有对它进行初始化,那么他就会获得基本类型的标准初始值,如果它是一个对象引用,那么它的默认初始值为null
    • 静态变量存放在方法区中。
  • 非静态变量存放在堆或栈空间里。
静态数据的初始化问题:

import static com.utils.Print.*;

 

class Bowl{

  

   Bowl(int marker)

   {

      println("Bowl(" + marker + ")");

   }

  

   void f1(int marker)

   {

      println("f1(" + marker + ")");

   }

}

 

 

class Table{

  

   static Bowl bowl1 = new Bowl(1);

  

   Table()

   {

      println("Table()");

      bowl2.f1(1);

   }

  

   void f2(int marker)

   {

      println("f2(" + marker + ")");

   }

  

   static Bowl bowl2 = new Bowl(2);

}

 

 

class Cupborad{

  

   Bowl bowl3 = new Bowl(3);

   static Bowl bowl4 = new Bowl(4);

  

   public Cupborad() {

      println("Cupborad()");

      bowl4.f1(2);

   }

  

   void f3(int marker)

   {

      println("f3(" + marker + ")");

   }

  

   static Bowl bowl5 = new Bowl(5);

}

 

 

public class StaticInitialization {

 

   static Table table = new Table();

   static Cupborad cupborad = new Cupborad();

 

   public static void main(String[] args) {

     

      println("Creating new Cupborad in main");

      new Cupborad();

      println("Creating new Cupborad in main");

      new Cupborad();

      table.f2(1);

      cupborad.f3(1);

   }

}

/*

   代码解析:

       初始化顺序: 先静态对象,后"非静态"对象。(静态对象中按照定义时书写顺序初始化)

         从输出结果中分析,要执行main()(静态方法),必须加载StaticInitialization类,然后其静态域tablecupborad被初始化,

       这将导致它们对应的类也被加载,并且由于它们也都包含静态的Bowl对象,因此Bowl虽有也被加载。

  

   总结创建过程:,假设有个名为Dog的类:

      1、即使没有显示地使用static关键字,构造器实际上也是静态方法。因此当首次创建类型为Dog的对象时(构造器可以看成静态方法),

      或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。

      2、然后载入Dog.class(这将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只是在Class对象首次加载的时候进行一次。

      3、当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。

      4、这块存储空间会被清零,这就自动地将Dog对象中所有的基本类型数据都设置成了默认值(对数字来说是0...)——这是通过将对象内存设置为二进制零二一举生成的,而引用则被设置成了null

      5、执行所有出现于字段定义出的初始化动作。

      6、执行构造器。

     

   注意:

      1static变量前可以有private修饰,表示这个变量可以在类的静态代码块中,或者类的其他静态成员方法中使用

      (当然也可以在非静态成员方法中使用),但是不能在其他类中通过类名来直接引用。

      2、每new一个对象,就会创建一个该类的实例,但无论创建多少个对象,static变量只创建一次。

*/


2、静态块的使用
 
     static代码块也叫静态代码块,是在类中独立于类成员的 static语句块,可以有多个,位置可以随便放 它不在任何的方法体内JVM加载类时会执行这些静态的代码块 ,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。

  java 静态代码块 静态方法区别

      一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,

      在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,这种代码是被动执行的静态方法在类加载的时候 就已经加载 可以用类名直接调用

      比如main方法就必须是静态的 这是程序入口

     

      两者的区别就是:

  • 静态代码块是自动执行的;
  • 静态方法是被调用的时候才执行的.

/*   

   类装载步骤

   Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:

   装载:查找和导入类或接口的二进制数据;

   链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;

   校验:检查导入类或接口的二进制数据的正确性;

   准备:给类的静态变量分配并初始化存储空间;

   解析:将符号引用转成直接引用;

   初始化:激活类的静态变量的初始化Java代码和静态Java代码块。

*/


静态代码块的初始化顺序:

class Parent {

  

   static String name = "hello";

  

   {

      System.out.println("parent block");

   }

  

   static

   {

      System.out.println("parent static block");

   }

 

   public Parent()

   {

      System.out.println("parent constructor");

   }

}

 

 

class Child extends Parent {

  

   static String childName = "hello";

  

   {

      System.out.println("child block");

   }

  

   static

   {

      System.out.println("child static block");

   }

 

   public Child()

   {

      System.out.println("child constructor");

   }

}

 

 

public class StaticIniBlockOrderTest {

 

   public static void main(String[] args) {

  

      new Child();//语句(*)

   }

}



/*   

   总结:

      对象的初始化顺序:首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,

      当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;

      父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。

      总之一句话,静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。

 */



静态代码块与非静态代码块的区别:

1、静态代码块是在类加载时自动执行的,非静态代码块在创建对象自动执行的代码,不创建对象不执行该类的非静态代码块。 顺序: 静态代码块--》非静态代码块--》类构造方法。

2、在静态方法里面只能直接调用同类中其他的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。因为对于非静态的方法和变量,需要先创建类的实例对象后方可使用,而静态方法在使用前不用创建任何对象。

3、如果某些代码必须要在项目启动时候就执行的时候,我们可以采用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,此时代码是被动执行的。


3、静态方法
  1. 静态方法可以直接通过类名调用,任何的实例也都可以调用
  2. 因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract
  3. 声明为static的方法一般有如下几个限制    
  • 它们仅能调用其他的static 方法。 
  • 它们只能访问static数据。 
  • 它们不能以任何方式引用this super
4、静态类
通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。

import static com.utils.Print.*;

 

public class StaticCls {

    public static void main(String[] args)

    {

       OuterCls.InnerCls oi = new OuterCls.InnerCls();

    }

}

 

class OuterCls {

   //声明一个静态类,只有内部类才能声明为静态类

    public static class InnerCls {

       InnerCls()

       {

           println("InnerCls");

       }

    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值