关于Java中的Static关键字

本文详细解析了Java中static关键字的作用,包括static变量、方法和类的特性与加载时机,通过示例展示了static如何实现独立于对象的共享状态和工具方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. static 关键字要解决的问题
  通常来说,当创建类时,就是在描述那个类的对象的外观与行为。除非用new创建那个对象,否则,实际上并未获得任何对象。执行new来创建对象的时候,数据存储空间才被分配,其方法才供外界调用。有两种情形用上述方法是无法解决的。一种情形是,只想为某特定域分配单一存储空间,而不去考虑究竟要创建多少个对象,甚至根本不需要创建任何对象。另一种情形是,希望某个方法不与包含他的类的任何对象关联在一起。也就是说,即使没有创建对象,也能够调用方法。简单来说,static的主要目的就是创建独立于具体对象的域变量与方法。

2. static修饰的变量或方法或类的加载时机
  在加载类的同时加在static修饰的部分。(注意:这个时候,还不存在具体对象,并且这个过程只进行一次)

3. 来分别看看静态变量、静态方法、静态类的效果

3.1 静态变量
public class StaticTest{

    public static int count =0;
    
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        StaticTest test1 = new StaticTest();
        System.out.println(test1.count);
        StaticTest test2 = new StaticTest();
        test2.count++;
        System.out.println(test1.count+" "+test2.count+" "+StaticTest.count);
    }

}

输出结果:
0
1    1    1

可见,static变量并不是所在类的某个具体对象所有,而是该类的所有对象所共有的,静态变量既能被对象调用,也能直接拿类来调用。
除此之外,静态变量不能引用非静态方法,原因正如前面描述静态加载时机中说的那样,加载静态的时候,非静态的变量、方法等还不存在,当然就无法引用了。但是,非静态方法或类却能正常引用静态变量或方法。因为非静态总是在静态之后出现的。

3.2 静态方法
  静态方法和静态变量一样,属于类所有,在类加载的同时执行,不属于某个具体的对象,所有对象均能调用。对于静态方法需要注意以下几点:
   它们仅能调用其他的static 方法。
   它们只能访问static数据。
   它们不能以任何方式引用this 或super。
class Simple {
    static void go() {
       System.out.println("Welcome");
    }
}
 
public class Cal {
    public static void main(String[] args) {
       Simple.go();
    }
}
  静态方法一般用于工具类中,可以直接拿类名调用工具方法进行使用。

3.3 静态类
  一般来说,一个普通类是不允许被声明为static的,但是,在内部类中可以将其声明为static的,这个时候,外部类可以直接调用内部类,因为static的内部类是在加载外部类的同时加载的,所以也就是说,并不要实例化外部类就能直接调用静态内部类。看例子:
public class BaseStatic {
  static {
        System.out.println("Load base static");
    }

    public BaseStatic(){
        System.out.println("BaseStatic constructor");
    }
    
    static class BaseInnerClass{
        static{
            System.out.println("Base inner class static");
        }
        
        public BaseInnerClass(){
            System.out.println("BaseInnerClass constructor");
        }
    }

}


public class StaticLoadOrderTest{

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new BaseStatic.BaseInnerClass();
    }

}

输出结果:
Base inner class static
BaseInnerClass constructor

分析:首先,在进入StaticLoadOrderTest的main方法之前,加载StaticLoadOrderTest类,然后执行new BaseStatic.BaseInnerClass();这里需要注意:因为BaseInnerClass是静态的,所以这里并不需要加载外部类和实例化外部类,可以直接加载BaseInnerClass并实例化。

3.4 关于静态加载顺序的示例
public class BaseStatic {
    static {
        System.out.println("Load base static");
    }
    
    public BaseStatic(){
        System.out.println("BaseStatic constructor");
    }
    
    static class BaseInnerClass{
        static{
            System.out.println("Base inner class static");
        }
        
        public BaseInnerClass(){
            System.out.println("BaseInnerClass constructor");
        }
    }

}

public class StaticLoadOrderTest {
    
    static {
        System.out.println("Load test");
    }
    
    public StaticLoadOrderTest(){
        System.out.println("Test constructor");
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new BaseStatic();
        new StaticLoadOrderTest();
        new BaseStatic.BaseInnerClass();
    }

}

输出结果:
Load test
Load base static
BaseStatic constructor
Test constructor
Base inner class static
BaseInnerClass constructor

分析:在进入main方法之前,需要加载StaticLoadOrderTest类,这时候发现有static代码块,先加载静态代码块,然后进入main方法内部,new BaseStatic(),这时候需要加载BaseStatic类,同时也要先加载静态代码块,然后调用构造器。注意:这里并没有加载BaseInnerClass,因为它是内部类只有在真正用到的时候才会进行加载,看到这个是不是又是一种单例设计模式的实现方式?回到main方法中,接下来该执行new StaticLoadOrderTest()了,因为StaticLoadOrderTest类之前已经被加载过一次了,并且类只加载一次,所以这里就直接构造了;然后是最后一句new BaseStatic.BaseInnerClass()了,和上面例子一样,这里就不再细讲。

转载于:https://www.cnblogs.com/Sky-Raining/p/10313197.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值