【Java面向对象】5-7 static 关键字详解

§5-7 static 关键字详解

在前面的章节(变量作用域、[非]静态成员)中已经了解了 static 关键字的用法和作用。本节将继续讨论 static 关键字的用途。

5-7.1 static 修饰的变量

我们来看一个例子:

public class Test {
    private static int num;			//静态变量:类变量
    private double figure = 0.0;	//非静态变量:实例变量
    
    public static void main(String args[]) {
        Test obj = new Test();		//实例化当前类
        
        Sout.println(Test.num);		//静态变量可以通过类名访问
        Sout.println(obj.num);		//静态变量还可以通过对象访问
        Sout.println(obj.figure);	//非静态变量仅可以通过对象访问
    }
}

运行结果:

0
0
0.0

可以看到,静态变量隶属于类,随类的加载而加载,被存储在静态方法区,只有一个,被所有线程共享,且具有初始值。因此,一般而言,可直接通过类名访问静态变量以显式区分该变量为静态变量。若需要多个类访问该变量,我们可以考虑使用静态变量,静态变量在多线程中也有很大的作用。

非静态变量可分为实例变量局部变量,前者隶属于对象,仅在类被实例化成对象后可通过对象访问,存储在堆中;后者属于局部变量,随着方法的运行一并被压入栈中,仅由当前线程使用,不共享,且不具有初始值,使用时必须初始化。

5-7.2 static 修饰方法

static 关键字还可以用于修饰方法,使其变为静态方法。还是上述同样的例子:

public class Test {
    public static void run() {
        //方法实现
    }
    
    public void go() {
        //方法实现
    }
    
    public static void main(String args[]) {
        Test.run();		//静态方法调用
        
        Test obj = new Test();
        obj.go();		//非静态方法调用
    }
}

同样地,静态方法随着类的加载而加载,隶属于类,可直接通过类名调用该方法,也可以通过对象调用该方法。若主方法也在该类中,还可以直接调用该方法而无需类名:

run();

且值得注意的是,静态方法进可以调用静态成员,不可以调用非静态成员。但非静态成员二者皆可调用。

并且,main(String args[]) 方法也是一个静态方法,若想在其中调用非静态成员,则必须先实例化才可调用。

5-7.3 静态代码块

代码还可以放在一个语句块当中,如:

public class Test {
    {
        //匿名代码块(不推荐)
        Sout.println("匿名代码块");
    }
    
    static {
        //静态代码块
        Sout.println("静态代码块");
    }
    
    public Test() {
        Sout.println("构造器");
    }
    
    public static void main(String args[]) {
        Test objA = new Test();
        Sout.println("============");
        Test objB = new Test();
    }
}

代码可以放在一个代码块之中。在类中,匿名代码块、静态代码块和构造器的执行顺序和执行次数稍有不同。运行上述程序,得到结果:

静态代码块
匿名代码块
构造器
============
匿名代码块
构造器

程序执行时,类最先被加载静态代码块随类的加载而加载并被执行,且只执行一次。而匿名代码块和构造器会随着对象的创建而执行,且有顺序:

静态代码块 -> 匿名代码块 -> 构造器

鉴于匿名代码块优先于构造器执行的性质,且在创建对象时执行,可以在匿名代码块中先对对象赋予初始值。

使用匿名代码块还可以用于限定局部变量的生命周期。匿名代码块中所声明的变量在该代码块执行完毕后立即被释放。这样可提高内存使用率。如:

public class Test {
    int x = 10;		//在匿名代码块外的局部变量
    
    {
        int y = 20;
        System.out.println(x);
        Sysyem.out.println(y);
    }
    
    System.out.println(x);
    System.out.println(y);		//报错,匿名代码块已经执行完毕,代码块内部局部变量被释放
}

不同于 C++,Java 不允许在匿名代码块中声明一个与代码块外重名的局部变量。即下列情况是不允许的:

public class Test {
    public void main(String args[]) {
        int x = 10;		//匿名代码块外的局部变量
        
        {
            int x = 20;	//匿名代码块内的重名变量 --->> 错误:作用域中已定义变量
            int y = 30; //匿名代码块内的局部变量
        }
    }
}

若尝试编译,则会报错(不通过),原因为:

image

5-7.4 静态导入包

已知 java.lang.Math 包下含有静态方法 random(); ,用于返回伪随机数。但每次调用时,需要语句:

Math.random();

但倘若可以省略类名,直接调用该类下的这个方法呢?这是我们则需要导入包:

import java.lang.Math.random;	//直接导入该包下的某个方法

但发现会报错:

image

但此时,将语句修改为下述语句即可:

import static java.lang.Math.radom;

同样地,我们还可以通过静态导入该包下的常量:

import static java.lang.Math.PI;

我们还可以使用通配符静态导入该包下所有静态成员:

import static java.lang.Math.*;

但是,使用静态导入时,应当注意

  1. 静态导入仅适用于导入静态成员;
  2. 当程序中大量调用某一包中的静态成员时,可用静态导入减少击键;
  3. 使用通配符可以导入包下所有静态成员
  4. 语法必须为 import static
  5. 提防成员二义性。若所导入的不同包中有同名静态成员,将会导致编译错误;
posted @ 2023-05-01 17:30  Zebt  阅读(141)  评论(0)    收藏  举报