java中的final怎么理解 final关键字的3种用法看完这篇全明白

java中的final怎么理解 final关键字的3种用法看完这篇全明白
最新回答
莎莎兔

2021-07-21 11:11:38

final关键字在Java中有三种主要用法:修饰变量、修饰方法和修饰类,分别用于实现不可变性、阻止方法重写和禁止继承。

  • 修饰变量final修饰变量时,表示该变量一旦被赋值则不可更改。

    final成员变量:必须在声明时或构造器中初始化。若类有多个构造器,每个构造器均需确保所有final成员变量被初始化。例如:public class MyClass { private final int x; // 必须初始化 public MyClass(int x) { this.x = x; // 在构造器中初始化 } public int getX() { return x; }}对于引用类型的final成员变量,final仅保证引用不可变(不能指向其他对象),但对象内部状态可修改。例如:public class MyClass { private final List<String> myList; public MyClass(List<String> list) { this.myList = list; // 初始化为传入的list } public void modifyList() { myList.add("new element"); // 合法:修改list内容 } public List<String> getMyList() { return myList; }}若需完全不可变,需使用不可变集合(如Guava的ImmutableList)或手动深拷贝对象。

    final局部变量:可在声明后赋值,但只能赋值一次。在lambda表达式和匿名内部类中,只能访问final或effectively final(初始化后未被修改)的局部变量。例如:public void myMethod() { final int y; y = 10; // 第一次赋值 // y = 20; // 错误:不能再次赋值}

  • 修饰方法final修饰方法时,表示该方法不能被子类重写,通常用于保护关键逻辑或提升性能。例如:

    public class Parent { public final void myMethod() { System.out.println("Parent's myMethod"); }}public class Child extends Parent { // @Override // public void myMethod() { // 编译错误:不能重写final方法 // System.out.println("Child's myMethod"); // }}

    final方法可提高代码安全性,防止子类意外修改父类行为。此外,编译器可能对final方法进行内联优化,提升执行效率。

  • 修饰类final修饰类时,表示该类不能被继承,通常用于创建不可变类或防止设计破坏。例如:

    public final class ImmutableClass { private final int x; public ImmutableClass(int x) { this.x = x; } public int getX() { return x; }}// class SubClass extends ImmutableClass { // 编译错误:不能继承final类// }

    String类是典型的final类,其不可变性使其在多线程环境中安全使用,并可作为HashMap的键。

final关键字的好处

  • 不可变性:保证变量、方法或类的状态不可变,提高代码可靠性和安全性。不可变对象更易理解和调试,且线程安全。
  • 性能优化:final方法允许编译器内联优化,提升执行效率。
  • 设计约束:强制执行设计约束,防止子类修改关键逻辑或破坏类设计。
  • 线程安全:final变量初始化后不会被修改,天然线程安全。

final与immutable的区别final仅保证引用不可变,而immutable要求对象状态在创建后不可修改。一个类要成为immutable,需满足:

  1. 类本身是final的。
  2. 所有成员变量是final的。
  3. 所有成员变量是immutable的,或通过防御性拷贝保护可变成员。
  4. 不提供修改对象状态的方法(如setter)。例如:
public final class ImmutablePerson { private final String name; private final int age; private final List<String> hobbies; // 必须是不可变集合或深拷贝 public ImmutablePerson(String name, int age, List<String> hobbies) { this.name = name; this.age = age; this.hobbies = new ArrayList<>(hobbies); // 防御性拷贝 } public String getName() { return name; } public int getAge() { return age; } public List<String> getHobbies() { return new ArrayList<>(hobbies); // 返回防御性拷贝 }}

实际应用场景

  • 配置常量:使用final static修饰常量存储配置信息。public class Config { public static final String DEFAULT_NAME = "default"; public static final int MAX_CONNECTIONS = 100;}
  • 缓存结果:使用final变量缓存计算结果,避免重复计算。public class CacheExample { private final int result; public CacheExample(int input) { this.result = calculate(input); } private int calculate(int input) { // 复杂计算逻辑 return input * 2; } public int getResult() { return result; }}
  • 构建不可变对象:使用final修饰类和成员变量,构建不可变对象(如Guava的ImmutableList)。
  • 模板方法模式:父类定义算法骨架,子类实现具体步骤。使用final修饰模板方法,防止子类修改骨架。public abstract class AbstractTemplate { public final void templateMethod() { step1(); step2(); step3(); } protected abstract void step1(); protected abstract void step2(); protected abstract void step3();}

性能影响理论上,final方法允许编译器内联优化,但实际效果因JVM智能优化而可能不明显。过度使用final可能降低代码可维护性,需在性能和可维护性间权衡。通常仅在性能瓶颈代码中考虑使用final优化。

总结理解final关键字的用法及其设计思想,对编写高质量Java代码至关重要。正确使用final可提升代码可靠性、安全性、可维护性和性能。