toc
63. Java 类和对象 - static
关键字
了解类成员:static
关键字
在 Java 中,static
关键字用于修饰字段和方法,使其成为类级别的成员,而非对象级别的成员。也就是说,被声明为 static
的成员与类本身绑定,无论创建多少个对象,它们都只有一份拷贝。这种特性使得 static
成为实现全局共享数据、工具方法以及常量的重要手段。
1. 类变量(static
字段)
1.1 与实例变量的区别
- 实例变量 :
- 每个对象都有独立的实例变量副本,存储在各自的内存中。
- 修改某个对象的实例变量只影响该对象,不会对其他对象产生影响。
- 类变量(static 字段) :
- 整个类中只有一份存储空间,所有对象共享同一份数据。
- 不管创建多少个该类的实例,类变量都只有一个,并且可以通过类名直接访问。
1.2 用法示例
下面的示例展示了如何使用 static
字段记录所有 Bicycle
对象的创建数量,同时为每个对象分配独一无二的 ID:
java
public class Bicycle {
// 实例变量,每个对象各自拥有
private int cadence;
private int gear;
private int speed;
private int id;
// 类变量:所有 Bicycle 实例共享,记录创建的数量
private static int numberOfBicycles = 0;
public Bicycle(int startCadence, int startSpeed, int startGear) {
this.cadence = startCadence;
this.speed = startSpeed;
this.gear = startGear;
// 每创建一个新对象,计数加 1,并将计数赋值给该对象的 id
id = ++numberOfBicycles;
}
public int getID() {
return id;
}
}
java
public static void main(String[] args) {
Bicycle bike1 = new Bicycle(3, 100, 50);
System.out.println(bike1.id);
Bicycle bike2 = new Bicycle(2, 80, 40);
System.out.println(bike2.id);
}
在这个示例中:
numberOfBicycles
为static
字段,记录了创建的Bicycle
数量,全类仅有一份,所有实例共享该数据。- 每个
Bicycle
对象都有自己的实例变量id
,用来区分不同对象。
1.3 访问类变量
- 推荐方式 :使用
类名.类变量名
访问,例如:Bicycle.numberOfBicycles
。这种方式能清晰地表明该变量是属于类的。 - 不推荐方式 :通过对象引用访问,如
myBicycle.numberOfBicycles
。这种方式容易让人误解为该变量是对象的专属属性,而非全局共享的。
java
System.out.println( Bicycle.numberOfBicycles);
System.out.println( bike1.numberOfBicycles);
System.out.println( bike2.numberOfBicycles);
2. 类方法(static
方法)
2.1 与实例方法的区别
- 实例方法 :
- 属于对象,必须先创建对象后才能调用。
- 调用方式:
对象名.方法名()
。
- 类方法(static 方法) :
- 属于类本身,可以直接通过
类名.方法名()
调用。 - 不依赖任何具体的对象实例。
- 属于类本身,可以直接通过
2.2 用法示例
假设我们想获取当前创建的 Bicycle
数量,可以通过以下 static
方法实现:
java
public class Bicycle {
// ...(其他成员同上)
// 类方法:无需对象即可调用,用于获取创建的 Bicycle 数量
public static int getNumberOfBicycles() {
return numberOfBicycles;
}
}
调用时只需使用:
java
int total = Bicycle.getNumberOfBicycles();
这样既直观又方便,无需先实例化对象。
2.3 注意事项:不能直接访问实例成员
由于 static
方法不属于任何具体对象,因此在方法体内无法直接使用实例变量或 this
关键字。例如:
java
public static void foo() {
// 编译错误:不能使用 this 或直接访问实例变量
// System.out.println(this.cadence);
}
如果需要访问实例数据,必须通过已有对象引用来访问:
java
public static void printBicycleSpeed(Bicycle bicycle) {
System.out.println("Speed: " + bicycle.speed);
}
3. 常量(static final)
在 Java 中,使用 static final
修饰的变量被称为常量,其值在程序运行过程中不能改变。这些常量通常在类加载时就被初始化,并且全类共享。
3.1 示例
java
public class MathConstants {
public static final double PI = 3.141592653589793;
public static final int MAX_VALUE = 100;
}
- final 表示常量一经赋值就不能再修改。
- static 表示常量是全类共享的,无需创建对象即可访问。
- 常量命名通常使用全大写字母,并用下划线
_
分隔单词,例如MAX_SPEED
、DEFAULT_CAPACITY
。
3.2 编译时常量
当常量的值在编译时已知(如上述 PI
),编译器可能会将代码中所有对该常量的引用直接替换为实际值,这样在性能上会更高效。但这也意味着若常量值修改,所有引用该常量的类都需要重新编译。
4. 使用 static
的注意事项与最佳实践
- 数据共享与全局状态 :
- 使用
static
字段可以方便地实现数据共享,例如计数器或全局配置信息。 - 过度依赖
static
变量可能导致代码间的耦合度增加,从而使单元测试和维护变得困难。
- 使用
- 工具方法与辅助函数 :
- 很多工具类(如
java.lang.Math
)中的方法都是static
的,因为这些方法不依赖对象状态,只提供通用功能。
- 很多工具类(如
- 线程安全 :
- 在多线程环境下使用
static
字段时要注意同步问题,因为多个线程可能同时访问和修改共享数据。
- 在多线程环境下使用
- 避免误用 :
- 切记不要滥用
static
。在设计时应仔细考虑某个方法或字段是否确实不依赖于对象状态,只有在确定其为全局共享的情况下再使用static
。
- 切记不要滥用
5. 综合示例
以下示例整合了类变量、类方法、实例变量及常量的用法,展示了如何设计一个既能统计对象数量,又能提供工具方法的类:
java
public class Bicycle {
// 实例变量,每个对象独有
private int cadence;
private int gear;
private int speed;
private int id;
// 类变量:所有 Bicycle 实例共享
private static int numberOfBicycles = 0;
// 类常量:不变的最大速度限制
public static final int MAX_SPEED = 50;
public Bicycle(int startCadence, int startSpeed, int startGear) {
this.cadence = startCadence;
this.speed = startSpeed;
this.gear = startGear;
// 对象计数自增
id = ++numberOfBicycles;
}
public int getID() {
return id;
}
// 类方法:返回已创建的 Bicycle 对象总数
public static int getNumberOfBicycles() {
return numberOfBicycles;
}
// 工具方法:判断给定速度是否超过最大速度限制
public static boolean isSpeedLegal(int speed) {
return speed <= MAX_SPEED;
}
// 实例方法:调整当前对象的速度
public void changeSpeed(int delta) {
int newSpeed = speed + delta;
if (isSpeedLegal(newSpeed)) {
speed = newSpeed;
} else {
System.out.println("超出允许的最大速度!");
}
}
}
在这个综合示例中:
- 使用
static
字段统计创建的Bicycle
数量。 - 通过
static
方法获取对象数量或判断速度是否合法。 - 使用
static final
常量MAX_SPEED
限制最大速度。 - 实例方法
changeSpeed
则根据对象当前状态进行操作,并利用工具方法进行判断。