1. 静态变量(静态域)
  2. 静态代码块
  3. 静态方法
  4. 静态类



1、静态变量


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


  • 非静态变量存放在堆或栈空间里。


静态数据的初始化问题:


import staticcom.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类,然后其静态域table和cupborad被初始化,

       这将导致它们对应的类也被加载,并且由于它们也都包含静态的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、执行构造器。

     

   注意:

      1、static变量前可以有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)




    {




oinew OuterCls.InnerCls();




    }




}




 




class OuterCls {




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




    public static class InnerCls {




       InnerCls()




       {




println("InnerCls");




       }




    }




}