static 关键字介绍

Java 中的 static 关键字主要用于内存管理。我们可以应用 Java static 关键字在变量、方法、代码块和内部类中。static 关键字属于类,而不是类的实例。
静态(static)修饰如下:

  • 变量:称为类变量、静态变量
  • 方法:称为类方法、静态方法
  • 代码块:称为静态代码块
  • 嵌套类:称为静态内部类

static 关键字的使用

静态变量

类的成员变量可以分为以下两种:

  1. 静态变量(或称为类变量),指被 static 修饰的成员变量。
  2. 实例变量,指没有被 static 修饰的成员变量。

静态变量与实例变量的区别如下:

1)静态变量

  • 运行时,Java 虚拟机只为静态变量分配一次内存,加载类过程中完成静态变量的内存分配。存在方法区的静态域中
  • 在类的内部,可以在任何方法内直接访问静态变量。
  • 在其他类中,可以通过类名访问该类中的静态变量。

2)实例变量

  • 每创建一个实例,Java 虚拟机就会为实例变量分配一次内存。
  • 在类的内部,可以在非静态方法中直接访问实例变量。
  • 在本类的静态方法或其他类中则需要通过类的实例对象进行访问。

静态变量在类中的作用如下:

  • 静态变量可以被类的所有实例共享,因此静态变量可以作为实例之间的共享数据,增加实例之间的交互性。
  • 如果类的所有实例都包含一个相同的常量属性,则可以把这个属性定义为静态常量类型,从而节省内存空间。例如,在类中定义一个静态常量 PI

调用关系

类变量实例变量
yesno
对象yesyes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.base.learn;

public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";

Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 40;
c1.nation = "CHN";

Chinese c2 = new Chinese();
c2.name = "马龙";
c2.age = 40;
c2.nation = "CHINA";

System.out.println(Chinese.nation); // CHINA
}
}

class Chinese {
String name;
int age;
static String nation;
}

静态方法

与成员变量类似,成员方法也可以分为以下两种:

  1. 静态方法(或称为类方法),指被 static 修饰的成员方法。
  2. 实例方法,指没有被 static 修饰的成员方法。

静态方法与实例方法的区别:

  1. 静态方法,属于类,而不属于类的对象。

    1. 它通过类直接被调用,无需创建类的对象。
    2. 静态方法中,不能使用 this 关键字,也不能直接访问所属类的实例变量和实例方法。
    3. 静态方法中,可以直接访问所属类的静态变量和静态方法。
    4. 同 this 关键字,super 关键字也与类的实例相关,静态方法中不能使用 super 关键字。
  2. 实例方法,可直接访问所属类的静态变量、静态方法、实例变量和实例方法。


静态方法非静态方法
yesno
对象yesyes

注意:关于静态属性和静态方法的使用,要从声明周期的角度去理解(随着类的加载而加载)

静态方法与静态变量好处:

  1. 属于类级别,无需创建对象就即可直接使用,使用方便。
  2. 全局唯一,内存中唯一,静态变量可以唯一标识某些状态。
  3. 类加载时候初始化,常驻在内存,调用快捷方便。

静态方法与静态变量缺点:

  1. 静态方法不能调用非静态的方法和变量。
  2. 不能使用 this 和 super 关键字。

静态方法与静态变量适用场景:

  1. 静态方法,最适合工具类中方法的定义;比如文件操作,日期处理方法等。
  2. 静态方法,适合入口方法定义;比如单例模式,因从外部拿不到构造函数,所以定义一个静态的方法获取对象非常有必要。
  3. 静态变量适合全局变量的定义;举例:用一个布尔型静态成员变量做控制标志。

static 的应用举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.base.learn;

public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
System.out.println("c1 的 ID:" + c1.getId());

Circle c2 = new Circle();
System.out.println("c2 的 ID:" + c2.getId());

Circle c3 = new Circle(3.4);
System.out.println("c3 的 ID:" + c3.getId());

System.out.println("创建圆的个数:" + Circle.getTotal());

}
}

class Circle {
private double radius; // 半径
private int id; // 编号,自动赋值
private static int total; // 记录创建圆的个数
private static int init = 1001;

public Circle() {
id = init++;
total++;
}

public Circle(double radius) {
this();
this.radius = radius;
}

// 求圆的面积
public double findArea() {
return Math.PI * radius * radius;
}

public double getRadius() {
return radius;
}

public void setRadius(double radius) {
this.radius = radius;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public static int getTotal() {
return total;
}
}

static 练习题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.base.learn;

/**
* 编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、
* “利率”、“最小余额”,定义封装这些属性的方法。
* 账号要自动生成。编写主类,使用银行账户类,输入、输出 3 个储户的上述信息。
* 考虑:哪些属性可以设计成 static 属性。
*/
public class Account {
private int id; // 账号
private String pwd = "000000"; // 初始密码
private double balance; // 存款余额

private static double interestRate; // 利率
private static double minMoney = 1.0; // 最小余额
private static int init = 1001; // 用于自动生成 ID

public Account() {
this.id = init++;
}

public Account(String pwd, double balance) {
this();
this.pwd = pwd;
this.balance = balance;
}

public String getPwd() {
return pwd;
}

public static double getInterestRate() {
return interestRate;
}

public static void setInterestRate(double interestRate) {
Account.interestRate = interestRate;
}

public static double getMinMoney() {
return minMoney;
}

public static void setMinMoney(double minMoney) {
Account.minMoney = minMoney;
}

public int getId() {
return id;
}

public double getBalance() {
return balance;
}

@Override
public String toString() {
return "Account{" +
"id=" + id +
", pwd='" + pwd + '\'' +
", balance=" + balance +
'}';
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.base.learn;

public class AccountTest {
public static void main(String[] args) {
Account acct1 = new Account();
Account acct2 = new Account("1234qwer", 2000);

Account.setInterestRate(0.012);
Account.setMinMoney(100);

System.out.println(acct1); // Account{id=1001, pwd='000000', balance=0.0}
System.out.println(acct2); // Account{id=1002, pwd='1234qwer', balance=2000.0}

}
}

静态代码块

后续在代码块文章中更新

静态内部类

后续在内部类文章中更新

参考