一. static 关键字介绍
Java 中的 static 关键字主要用于内存管理。我们可以应用 Java static 关键字在变量、方法、代码块和内部类中。static 关键字属于类,而不是类的实例。
静态(static)修饰如下:
- 变量:称为类变量、静态变量
- 方法:称为类方法、静态方法
- 代码块:称为静态代码块
- 嵌套类:称为静态内部类
二. static 关键字的使用
2.1 静态变量
类的成员变量可以分为以下两种:
- 静态变量(或称为类变量),指被 static 修饰的成员变量。
- 实例变量,指没有被 static 修饰的成员变量。
静态变量与实例变量的区别如下:
1)静态变量
- 运行时,Java 虚拟机只为静态变量分配一次内存,加载类过程中完成静态变量的内存分配。存在方法区的静态域中
- 在类的内部,可以在任何方法内直接访问静态变量。
- 在其他类中,可以通过类名访问该类中的静态变量。
2)实例变量
- 每创建一个实例,Java 虚拟机就会为实例变量分配一次内存。
- 在类的内部,可以在非静态方法中直接访问实例变量。
- 在本类的静态方法或其他类中则需要通过类的实例对象进行访问。
静态变量在类中的作用如下:
- 静态变量可以被类的所有实例共享,因此静态变量可以作为实例之间的共享数据,增加实例之间的交互性。
- 如果类的所有实例都包含一个相同的常量属性,则可以把这个属性定义为静态常量类型,从而节省内存空间。例如,在类中定义一个静态常量 PI
调用关系:
类变量 | 实例变量 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
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;
}
2.2 静态方法
与成员变量类似,成员方法也可以分为以下两种:
- 静态方法(或称为类方法),指被 static 修饰的成员方法。
- 实例方法,指没有被 static 修饰的成员方法。
静态方法与实例方法的区别:
- 静态方法,属于类,而不属于类的对象。
- 它通过类直接被调用,无需创建类的对象。
- 静态方法中,不能使用 this 关键字,也不能直接访问所属类的实例变量和实例方法。
- 静态方法中,可以直接访问所属类的静态变量和静态方法。
- 同 this 关键字,super 关键字也与类的实例相关,静态方法中不能使用 super 关键字。
- 实例方法,可直接访问所属类的静态变量、静态方法、实例变量和实例方法。
调用关系:
静态方法 | 非静态方法 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
注意:关于静态属性和静态方法的使用,要从声明周期的角度去理解(随着类的加载而加载)
静态方法与静态变量好处:
- 属于类级别,无需创建对象就即可直接使用,使用方便。
- 全局唯一,内存中唯一,静态变量可以唯一标识某些状态。
- 类加载时候初始化,常驻在内存,调用快捷方便。
静态方法与静态变量缺点:
- 静态方法不能调用非静态的方法和变量。
- 不能使用 this 和 super 关键字。
静态方法与静态变量适用场景:
- 静态方法,最适合工具类中方法的定义;比如文件操作,日期处理方法等。
- 静态方法,适合入口方法定义;比如单例模式,因从外部拿不到构造函数,所以定义一个静态的方法获取对象非常有必要。
- 静态变量适合全局变量的定义;举例:用一个布尔型静态成员变量做控制标志。
static 的应用举例
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 练习题
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 +
'}';
}
}
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}
}
}
2.3 静态代码块
链接后续补充
2.4 静态内部类
链接后续补充
参考:
https://zhuanlan.zhihu.com/p/259368621
https://blog.csdn.net/jiahao1186/article/details/121886704