Java学习笔记之深入理解关键字static

基本概念

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量这个概念。
在Java中,用static修饰的方法称为静态方法(类方法),用static修饰的变量称为静态变量(类变量)。
为什么需要static关键字?可以通过以下两种情形进行思考

  • 情形一:只想为某特定域分配单一存储空间,而不去考虑究竟要创建多少对象,甚至根本就不创建任何对象。
  • 情形二:希望某个方法不与包含它的类的任何对象关联在一起。也就是说,即使没有创建对象,也可以调用这个方法。

一般情况下,执行new来创建对象时,数据存储空间才被分配,其方法才供外界调用。要想解决以上两种情形,通过new肯定是不行的,而通过static关键字就可以满足这两方面的需要。
static有以下几个特点:

  • 被static修饰的成员变量和成员方法独立于该类的任何对象。即不依赖于类特定的实例,被类的所有实例共享
  • static变量和方法可以直接通过类来访问,而无需创建任何对象
  • static方法是没有this的方法,即它不属于对象,而是属于类
  • 在static方法内部不能访问非静态成员变量和非静态成员方法,因为非静态成员变量/方法是依赖于具体的对象,必须创建对象后才能使用(非绝对)
  • 类的构造器实际上也是静态方法,只不过没有显示地声明

static变量

类成员变量可分为两类:静态变量和实例变量。静态变量不属于某个实例对象,而是属于类;而实例变量属于某个对象的属性。可通过以下代码进行理解

public class Test {
    static int a;
    int b;
  public static void main(String[] args) {
      Test test1 = new Test();
      System.out.println(a);
      //System.out.println(b);       //It's not OK!   
      System.out.println(test1.b);   //It's OK!

      Test test2 = new Test();
      a = 1;
      test2.b = 1;
      System.out.println(a); 
      System.out.println(test1.b);
      System.out.println(test2.b);
  }
} 

输出结果:

0
0
1
0
1

具体区别可参考Java学习笔记之变量类型

static方法

静态方法可以直接通过类名调用,任何的实例也都可以调用。但在static方法内部不能访问非静态成员变量和非静态成员方法,因为非静态成员变量/方法是依赖于具体的对象,必须创建对象后才能使用。这种说法不是完全绝对的,因为:如果传递一个对象的引用到静态方法里,然后通过这个引用就可以调用非静态方法和访问非静态数据成员了。但通常要达到这样的效果,我们只需写一个非静态方法即可,而无需传递引用。可通过以下代码进行理解:

public class staticDemo {
    public void print() {
        System.out.println("staticDemo!");
    }
    // 静态方法
    public static void printStatic() {
        //print(); // It's not OK!
        staticDemo demo = new staticDemo();
        demo.print(); // 在静态方法中调用非静态方法必须先创建对象
    }
    // 非静态方法
    public void printNoStatic() {
        print();
    }
}

static代码块

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

class Person{
    private Date birthDate;

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }

    boolean isBornBoomer() {
        Date startDate = Date.valueOf("1946");
        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好:

class Person{
    private Date birthDate;
    private static Date startDate,endDate;
    static{
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    }

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }

    boolean isBornBoomer() {
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

静态代码块的执行顺序可根据以下代码进行理解:

class StaticCode  
{  
    static   
    {  
        System.out.println("A");  
    }  
    public void show()  
    {  
        System.out.println("Hello World !");  
    }  
}
class StaticCodeDemo {
    static   
    {  
        System.out.println("B");  
    }  
    public static void main(String[] args)  
    {  
        new StaticCode().show();  
    }  
    static  
    {  
        System.out.println("C");  
    }  
}

输出结果:

B
C
A
Hello World !

static和final一起使用

  • 对于static final修饰的变量,表示一旦赋值就不可修改,并且可通过类名直接访问
  • 对于static final修饰的方法,表示该方法不可覆盖,并且可通过类名直接调用

对于static final修饰的引用类型对象,特别是容器类型(如ArrayList、HashMap),不可以改变容器对象本身(即不能改变将其引用指向其他对象),但可以修改容器中存放的对象。

可通过以下程序进行理解:

import java.util.ArrayList;

public class StaticFinalDemo {
    private static final String STR_STATIC_FINAL = "a";
    private static String strStatic = "b";
    private final String strFinal = "c";
    private static final ArrayList < String > ARRAY_LIST = new ArrayList < String > ();

    private void print() {
        System.out.println("-------------值处理前----------");
        System.out.println("STR_STATIC_FINAL = " + STR_STATIC_FINAL);
        System.out.println("strStatic = " + strStatic);
        System.out.println("strFinal = " + strFinal);
        System.out.println("ARRAY_LIST = " + ARRAY_LIST);
        // STR_STATIC_FINAL = "aa"; // It's not OK! final表示终态,不可以改变变量本身
        strStatic = "bb"; // 可进行更改
        // strFinal = "cc"; // It's not OK! final表示终态,不可以改变变量本身
        // ARRAY_LIST = new ArrayList<String>(); // It's not OK! final表示终态,不可以将ARRAY_LIST引用指向其他对象
        ARRAY_LIST.add("d"); // 可以修改容器中存放的对象
        System.out.println("-------------值处理后----------");
        System.out.println("STR_STATIC_FINAL = " + STR_STATIC_FINAL);
        System.out.println("strStatic = " + strStatic);
        System.out.println("strFinal = " + strFinal);
        System.out.println("ARRAY_LIST = " + ARRAY_LIST);
    }
    public static void main(String args[]) {
        new StaticFinalDemo().print();
    }
}

输出结果:

-------------值处理前----------
STR_STATIC_FINAL = a
strStatic = b
strFinal = c
ARRAY_LIST = []
-------------值处理后----------
STR_STATIC_FINAL = a
strStatic = bb
strFinal = c
ARRAY_LIST = [d]

参考资料

  1. Java编程思想
  2. Java中的static关键字解析
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值