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

来源:互联网 发布:printthis.js用法 编辑:程序博客网 时间:2024/06/05 20:29

基本概念

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);  }} 

输出结果:

00101

具体区别可参考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");      }  }

输出结果:

BCAHello 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 = astrStatic = bstrFinal = cARRAY_LIST = []-------------值处理后----------STR_STATIC_FINAL = astrStatic = bbstrFinal = cARRAY_LIST = [d]

参考资料

  1. Java编程思想
  2. Java中的static关键字解析
1 0
原创粉丝点击