static和final关键字

该文章已生成可运行项目,

目录

static 关键字

static 的主要用法

1.静态变量(类变量)

2 静态方法

3 静态代码块

4 静态内部类

static 的注意事项

1 生命周期

2 访问限制

3 内存分配

4 在 JVM 层面:

5 继承与覆盖

6 线程安全

使用场景

final 关键字

final 的基本用法

1 final 修饰类

2 final 修饰方法

3 final 修饰变量

final 成员变量

final 静态变量

final 的注意事项

1 final 与不可变性

2 初始化时机

3 final+static

4 final类不能被继承,但可以实例化对象

5.final 变量初始化的两种场景(成员变量和局部变量)

使用场景

常见误区

补充:String 不可变的真正原因


static 关键字

static 是 Java 中一个非常重要的关键字,它可以用来修饰变量、方法、代码块和内部类不能修饰外部类(顶级类,Top-Level Class),static不能修饰构造器

外部类

  • static 表示"属于类而不属于实例",但外部类本身就是一个独立的类,没有"所属对象"的概念,所以 static 修饰无意义。
  • Java 语法规定,外部类只能用 public、final、abstract 或无修饰符(default 包访问权限)修饰,不能用 static。

static 的主要用法

1.静态变量(类变量)
  • 用 static 修饰的变量属于类,而不是类的某个实例
  • 所有实例共享同一个静态变量
  • 在类加载时初始化
2 静态方法
  • 静态方法属于类,而不是类的实例
  • 可以直接通过类名调用
  • 静态方法中不能直接访问非静态成员(变量或方法) 静态方法不能直接调用非静态方法,因为静态方法在执行时,没有类的实例上下文,无法访问实例变量和实例方法。如果静态方法需要调用非静态方法,可以通过创建类的实例来间接调用。
  • 在 Java 中,静态方法本身并不需要 “初始化”,因为它们是类的一部分,而不是实例的一部分。静态方法在类加载到 JVM 时就可以被调用。不过,如果静态方法依赖于静态变量或静态代码块初始化的值,那么这些静态变量和静态代码块会在类加载时初始化。
3 静态代码块
  • 用于初始化静态变量
  • 在类加载时执行,且只执行一次
  • 可以有多个静态代码块,按顺序执行
4 静态内部类
  • 静态内部类不依赖于外部类的实例
  • 可以访问外部类的静态成员
  • 不能访问外部类的非静态成员

static 的注意事项

1 生命周期
  • 静态成员的生命周期与类相同,从类加载开始到程序结束
  • 非静态成员的生命周期与对象实例相同
2 访问限制

静态方法中:

  • 可以直接访问其他静态成员
  • 不能直接访问非静态成员(需要通过对象实例访问
  • 不能使用 this 和 super 关键字(这两个关键字是对象层面的)
3 内存分配
  • 静态成员存储在方法区(Method Area)中
  • 非静态成员存储在堆内存
4 在 JVM 层面:
  • 类初始化由 <clinit> 方法处理(静态代码块和静态变量初始化)
  • 对象构造由 <init> 方法处理(构造器代码)
5 继承与覆盖
  • 静态方法可以被继承,但不能被覆盖(Override)
  • 子类中的同名静态方法会隐藏(Hide)父类的静态方法
class Parent {
    static void show() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    static void show() {
        System.out.println("Child");
    }
}

public class Test {
    public static void main(String[] args) {
        Parent p = new Child();
        p.show();  // 输出 "Parent",不是多态
    }
}
6 线程安全
  • 静态变量是共享资源,在多线程环境下需要考虑线程安全问题
  • 可以使用同步机制(synchronized)或 volatile 关键字保证线程安全

使用场景

  • 工具类方法:如 Math 类中的各种数学计算方法
  • 常量定义:使用 static final 组合定义常量
  • 共享数据:需要在所有实例间共享的数据
  • 单例模式:实现单例设计模式
  • 工厂方法:创建对象的静态工厂方法

final 关键字

final 是 Java 中一个非常重要的关键字,它可以用来修饰类、方法、变量(包括局部变量、成员变量和静态变量)不能修饰构造器

final 的基本用法

1 final 修饰类

当一个类被声明为 final 时,它不能被继承。

应用:

  • String 类就是 final 的,确保其不可变性(非唯一原因,但是关键防御手段)
  • 工具类通常声明为 final 防止被继承
2 final 修饰方法

final 方法不能被子类覆盖\重写(Override)。

应用:

  • 不希望子类改变的方法
  • 模板方法设计模式中的固定步骤
3 final 修饰变量

final 变量一旦被初始化后就不能再修改。

(1 )基本类型变量:

final int x = 10;
x = 20; // 编译错误:Cannot assign a value to final variable 'x'

(2)引用类型变量

final List<String> list = new ArrayList<>();
list.add("Hello"); // 允许,修改的是对象内容
list = new ArrayList<>(); // 编译错误:Cannot assign a value to final variable 'list'

(3)final 参数

void process(final int param) {//由调用方法时传入的值初始化
    param = 10; // 编译错误
}
final 成员变量

必须在声明时或构造器或代码块中初始化:

但注意在构造器中初始化的时候,每个构造器都要加初始化语句(这可以用代码块优化)

class MyClass {
    final int x; // 1.可以在定义时直接赋值

    {
        x=0;    //2.代码块中初始化
    }
    

//    MyClass(int value) {//3.构造器中赋值
//       x = value;
//    }

}
final 静态变量

必须在声明或静态代码块中初始化;不能在构造器中初始化。

final 的注意事项

1 final 与不可变性
  • final 修饰基本类型:值不可变
  • final 修饰引用类型:引用不可变,但对象内容可变

要实现完全不可变类,需要:

  • 所有字段 final
  • 类本身 final(或构造器 private) ,这里类final修饰了,方法就可以不用final了
  • 不提供修改内部状态的方法
2 初始化时机
  • final 实例变量必须在构造完成前初始化
  • final 静态变量必须在类加载完成前初始化
3 final+static

     final和static往往搭配使用,效率更高,不会导致类加载(只调用类中的final+static修饰的常量时,不会导致类被加载)

4 final类不能被继承,但可以实例化对象
5.final 变量初始化的两种场景(成员变量和局部变量)
特性final 成员变量final 局部变量
初始化要求必须在声明、构造器或初始化块中赋值只需在使用前赋值一次
作用域整个类范围内有效仅在声明它的代码块内有效
默认值无(必须显式初始化)无(必须显式初始化)
典型用途定义不可变对象属性确保局部计算过程中值不被修改

      局部变量:

void example() {
    final int x;    // 声明时不初始化(空白final)
    x = 10;        // 第一次赋值
    // x = 20;     // 编译错误:不能再次赋值
    System.out.println(x);
}
void process(boolean flag) {
    final int result;
    
    if (flag) {
        result = 1;
    } else {
        result = 2;
    }
    
    System.out.println(result);  // 确保在任何路径下都已初始化
}
void loadConfig() {
    final String config;
    
    try {
        config = readConfigFile();  // 可能抛出异常
    } catch (IOException e) {
        config = "default";         // 确保异常情况下也有值
    }
    
    System.out.println(config);
}

使用场景

  • 尽量使用 final 修饰不会改变的变量:提高代码可读性和安全性
  • 不可变类优先使用 final 字段:简化并发编程
  • 工具类声明为 final:防止被继承
  • 常量使用 public static final:遵循命名规范(全大写,下划线分隔)

常见误区

  • 认为 final 对象完全不可变:实际只是引用不可变
  • 忽略空白 final 的初始化要求:导致编译错误

补充:String 不可变的真正原因

关键设计作用
1. final 修饰类防止子类继承并重写方法破坏不可变性(如覆盖 toCharArray() 返回可变数组)。
2. private final 字段存储字符数据的 char[] value 是 private final,外部无法直接修改。
3. 无修改数据的公开方法所有看似修改的方法(如 concat()replace())都返回新 String 对象
4. 保护性拷贝构造 String 时,如果传入外部 char[],会拷贝一份新数组(避免外部修改影响)。
本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值