Java 中的 static 和 final 关键字

1. static 关键字

static 是 Java 中用于声明静态成员(字段、方法、代码块或内部类)的关键字。静态成员属于类,而不是类的实例(对象)。这意味着静态成员可以在没有创建对象的情况下被访问。

1.1 静态字段(Static Variables)

  • 定义:静态字段是属于类的,而不是类的实例。这意味着所有实例共享相同的静态字段。
  • 特点:静态字段在内存中只有一份拷贝,所有对象共享这一份数据。

语法

1
2
3
class MyClass {
static int staticVar = 0; // 静态字段
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
static int count = 0; // 静态字段

MyClass() {
count++;
}
}

public class Main {
public static void main(String[] args) {
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
System.out.println(MyClass.count); // 输出:2
}
}

在这个示例中,count 是静态字段,所有实例都共享这个字段,因此无论创建多少个对象,count 的值都会累加。

1.2 静态方法(Static Methods)

  • 定义:静态方法属于类,可以通过类名直接调用,而不需要创建实例对象。
  • 特点:静态方法只能访问类中的静态字段和静态方法,不能直接访问实例字段和实例方法。

语法

1
2
3
4
5
class MyClass {
static void staticMethod() {
System.out.println("这是一个静态方法");
}
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
static int count = 0;

static void incrementCount() {
count++;
}
}

public class Main {
public static void main(String[] args) {
// 通过类名调用静态方法
MyClass.incrementCount();
System.out.println(MyClass.count); // 输出:1
}
}

静态方法可以直接通过类名调用,而不需要创建类的实例。

1.3 静态代码块(Static Block)

  • 定义:静态代码块是在类加载时执行的一段代码,用于初始化静态成员变量,或者执行一些初始化操作。
  • 特点:静态代码块在类加载时执行一次,并且只执行一次。

语法

1
2
3
4
5
6
class MyClass {
static {
// 静态初始化块
System.out.println("类加载时执行的代码");
}
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass {
static {
System.out.println("类 MyClass 被加载");
}
}

public class Main {
public static void main(String[] args) {
// 静态块在第一次访问该类时执行
MyClass obj = new MyClass(); // 输出:类 MyClass 被加载
}
}

在上述代码中,MyClass 类的静态块在第一次创建对象时执行。静态代码块通常用于初始化静态变量或者进行类级别的资源配置。

1.4 静态内部类(Static Inner Classes)

  • 定义:静态内部类是属于外部类的,而不是外部类的实例。静态内部类可以直接访问外部类的静态成员,但不能访问外部类的实例成员。

语法

1
2
3
4
5
6
7
8
9
class Outer {
static int x = 10;

static class Inner {
void display() {
System.out.println(x); // 访问外部类的静态字段
}
}
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Outer {
static int x = 10;

static class Inner {
void display() {
System.out.println("外部类的静态字段 x: " + x);
}
}
}

public class Main {
public static void main(String[] args) {
Outer.Inner obj = new Outer.Inner();
obj.display(); // 输出:外部类的静态字段 x: 10
}
}

2. final 关键字

final 关键字用于修饰类、方法和变量,表示它们不能被修改。具体来说,final 关键字的作用如下:

2.1 final 修饰类(不可继承)

  • 定义:使用 final 修饰的类不能被继承。换句话说,final 类不能有子类。

语法

1
2
3
final class MyClass {
// 该类不能被继承
}

示例

1
2
3
4
5
6
7
8
final class MyClass {
void display() {
System.out.println("不能被继承的类");
}
}

// 下面的代码会报错
// class SubClass extends MyClass {} // 编译错误:不能继承 final 类

2.2 final 修饰方法(不可重写)

  • 定义:使用 final 修饰的方法不能被子类重写。这样可以防止方法的行为被改变。

语法

1
2
3
4
5
class Parent {
final void display() {
System.out.println("不能被重写的方法");
}
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
class Parent {
final void display() {
System.out.println("不能被重写的方法");
}
}

class Child extends Parent {
// 下面的代码会报错
// void display() { // 编译错误:不能重写 final 方法
// System.out.println("尝试重写父类的方法");
// }
}

2.3 final 修饰变量(常量)

  • 定义:使用 final 修饰的变量是常量。常量一旦被初始化后,它的值不能再修改。final 变量必须在声明时或者构造函数中进行初始化。

语法

1
final int x = 10;  // 常量

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
final int CONSTANT_VALUE = 100;

void display() {
// CONSTANT_VALUE = 200; // 编译错误:常量不能被修改
System.out.println("常量值: " + CONSTANT_VALUE);
}
}

public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.display(); // 输出:常量值: 100
}
}

2.4 final 修饰参数(不能修改参数值)

  • 定义final 还可以用于修饰方法参数,表示该参数的值不能在方法内部修改。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyClass {
void display(final int x) {
// x = 10; // 编译错误:final 参数不能修改
System.out.println("参数值: " + x);
}
}

public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.display(5); // 输出:参数值: 5
}
}

3. staticfinal 的组合使用

staticfinal 常常一起使用,特别是在定义常量时。常量通常是 static 的,因为它们属于类,而不是实例;同时是 final 的,因为常量值不能被修改。

示例

1
2
3
4
5
6
7
8
9
class Constants {
public static final int MAX_VALUE = 100;
}

public class Main {
public static void main(String[] args) {
System.out.println("最大值: " + Constants.MAX_VALUE);
}
}

在这个例子中,MAX_VALUE 是一个常量,使用了 static final,它表示这个常量属于 Constants 类,而不属于任何具体的实例,并且它的值是固定的,不能被改变。

4. 总结

  • static 用于声明静态成员,它们属于类而不是类的实例,常用于类级别的数据或方法。
  • final 用于声明常量、不可继承的类、不可重写的方法以及不可修改的参数和局部变量,确保它们的不可变性。