对java中static关键字的理解

时间:2021-07-15 19:17:18

        static可以声明静态变量、静态方法、静态类、代码块。

     静态变量:

     当我们需要一个可以全局访问的对象时, 我们首先想起静态变量/对象, 因为它是当前进程中的唯一引用, 但不一定是唯一对象(看看多线程时的单例模式就明白了)。

     代码很简单: public static int value或Object obj。


     静态方法:

      就是在类成员方法前添加static关键字, 从而在其它类可以直接引用该方法, 不再通过类实例找到该方法。、

     例如:public class Demo {

                       public static void method() {

                       }

               }


      静态类:

      只能定义在一个外部类中, 即只有静态内部类, 见其它博文介绍, 项目中很少使用(单例模式可能会用到)。


      代码块:

       有时需要只需要执行一次若干行代码, 这时可以用静态代码块, 加载含有静态代码类时1. 先执行类静态成员变量, 2. 再执行静态代码块。 3. 执行类构造函数。

      例如: public class demo {

                        private int a;

                        ...                //声明类成员变量

                        static {

                               method1();

                               method2();

                        }

                 }

  写的比较少, 我们通过示例代码加深对static的理解:

代码1:

         public class FatherClass {
               public static void show() {
                   System.out.println("FatherClass show: ");
                }
    
                public static void showExt() {
                   System.out.println("FatherClass showExt");
                }
          }

         public class ChildClass extends FatherClass {
                public static void show() {
                   System.out.println("ChildClass show");  //静态方法也能覆盖???会是多态吗? 仔细考虑一下
                  }
          }


        FatherClass.show();
        ChildClass.show();
        
        FatherClass obj = new ChildClass();
        obj.show();
        obj.showExt();

        想想会输出什么?  obj.show()输出父类还是子类的方法?

FatherClass show: 
ChildClass show
FatherClass show: 
FatherClass showExt

       很意外吗? 静态方法是不能被继承或者覆盖的, 子类保存了父类的引用, 所以能调用父类的方法(如showExt函数)。当父类、子类都有相同方法时(如show函数), 调用时只会找声明该对象的类(如FatherClass)中的方法。


再看个例子:

class A {
private B b = new B();
private static C c = new C();
public A() {
System.out.println("A construct");
}
static {
System.out.println("A static");
}
}


class B {
public B() {
    System.out.println("B construct");
}
}


class C {
public C() {
System.out.println("C construct");
}
}


public class MapMain {
   
public static void main(String[] args) {
// TODO Auto-generated method stub
        A a;  
        
        a = new A();  
        
        a = new A();
}
}

A a这行代码会有输出吗?  答案是没有, 因为还没有真正的加载类A。


第一行a = new会输出什么?先看答案。

C construct
A static
B construct
A construct

我们看到了, 当加载一个类时先执行类静态变量、再静态代码块、类成员变量、构造函数等。


那么第二a = new A()呢? 因为前面说静态变量只有一个,静态代码块只执行一次, 所以会输出

B construct
A construct

我们看到类静态成员对象只会实例化一次, 这也是用它实现线程安全单例模式的原因。