Final可用在哪些位置? 分别表示什么作用?

本文详细探讨了Java中final关键字的用法,包括final修饰类、方法和变量的含义和效果。final修饰的类不可被继承,final方法无法被重写,JVM可能尝试对final方法进行内联优化。final变量一旦初始化后不可改变,引用类型时仅引用不可变,内容可变。final常量在编译阶段存入常量池。


前言

速记

  1. 被final修饰的类不可以被继承
  2. 被final修饰的方法不可以被重写
  3. 被final修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变。
  4. 被final修饰的方法,JVM会尝试将其内联,以提高运行效率(早期java)
  5. 被final修饰的常量,在编译阶段会存入常量池中。

一、final修饰类

当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。

在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。
在这里插入图片描述
简单来说就是字面意思的最终类。

二、final修饰方法

1.被final修饰的方法不可以被重写

在这里插入图片描述
当然如果你用final修饰一个private方法,然后继承类后写一个一样的方法,会出现看似重写的情况,但这只是自欺欺人。因为这种方法下,你前面那个final方法本来就没有被继承,你只是重新写了一个一样的方法,

public class Test {
    private final void say(){
        System.out.println("说Test");
    }
}

class Test_final_class extends Test{
    public void say(){
        System.out.println("说Test1");
    }
}

2.被final修饰的方法,JVM会尝试将其内联,以提高运行效率(早期java)

下面这段话摘自《Java编程思想》第四版第143页:
“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“

实际上这本书是2007年出版的了,因此它的最近java版本理论上应该都投入工程实践了。因此这个优化等于没说。

三、final修饰变量

1.被final修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变。

对于一个final变量,
如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象,但是你可以修改其内的属性。

final int a = 100;
a = 101;//报错
final int[] list = new int[]{1};
list = new int[]{2};//报错
list[0] = 2;

因此理解一下:
final修饰变量的本质是final修饰的变量会指向一块固定的内存, 这块内存中的值不能改变.
而引用对象是在这块内存里指向的是对象的引用,对象的相关属性在另外的内存放着。

2.被final修饰的常量,在编译阶段会存入常量池中。

public static void main(String[] args) {
	int n1 = 2021;          //普通变量
	final int n2 = 2021;    //final修饰的变量
	
	String s = "2021优快云";
	String s1 = n1 + "优快云";	//拼接字符串"2021优快云"
	String s2 = n2 + "优快云";
	
	System.out.println(s == s1);	//false
	System.out.println(s == s2);	//true
}

拼接s2时,由于n2和“优快云”都是常量,所以可以直接将“2021优快云”返回给s2即可,不必等到运行时再拼接。
由于被final修饰的常量会在编译期进入常量池, 如果有涉及到该常量的操作, 很有可能在编译期就已经完成。


总结

final可以用于修饰类,方法,变量。
作用分别是:

  1. 被final修饰的类不可以被继承
  2. 被final修饰的方法不可以被重写
  3. 被final修饰的方法,JVM会尝试将其内联,以提高运行效率(早期java。
  4. 被final修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变
  5. 被final修饰的常量,在编译阶段会存入常量池中。
<think>我们正在回答用户关于Java原子类的问题。用户的问题包括:原子类是什么、有哪些、原理作用。 根据引用内容,我们可以知道: 1. 原子类是在java.util.concurrent.atomic包下的类,用于在多线程环境下进行无锁的原子操作。 2. 原子类分为6种类型:基本类型原子类、数组类型原子类、引用类型原子类、原子更新属性、Adder加法器、积累器。 3. 原子类的原理主要是利用CAS(Compare and Swap)操作,这是一种无锁技术,由硬件指令支持。 4. 原子类的作用是提供线程安全的操作,避免了使用锁带来的性能开销,特别适用于计数器等场景。 我们还需要注意引用中提到的: - 原子类不是普通包装类的替代品,它们没有重写equals、hashCode等方法。 - 原子类在高并发场景下性能优越,如LongAdder在高度竞争时比AtomicLong性能更好。 因此,我们的回答结构可以如下: 1. 定义:什么是原子类? 2. 分类:列举6种类型,并给出每个类型的代表类。 3. 原理:重点讲解CAS,以及LongAdder等类的优化原理(分段CAS)。 4. 作用:为什么使用原子类?与锁相比的优势,适用场景。 同时,我们还可以给出一个简单的示例(如AtomicInteger的递增)来说明用法。 最后,生成相关问题。 注意:引用标记要正确,例如引用[1]是关于atomic包的介绍,引用[2]是关于AtomicInteger的示例注意事项,引用[3]是关于LongAdder的性能优势。</think>### Java 原子类详解 #### **1. 什么是原子类?** Java 原子类(`java.util.concurrent.atomic` 包)是**线程安全的工具类**,通过硬件级原子指令(如 CAS)实现**无锁并发操作**,避免传统锁的性能开销[^1]。核心特性: - **原子性**:操作不可中断(如 `getAndIncrement()`) - **无锁设计**:基于 CAS 自旋而非阻塞 - **轻量级**:适用于简单共享变量的并发控制 #### **2. 原子类分类(6种类型)**[^1] | **类型** | **代表类** | **作用** | |-----------------------|-------------------------------|-----------------------------------| | **基本类型原子类** | `AtomicInteger`, `AtomicLong` | 原子更新整型/长整型变量 | | **数组类型原子类** | `AtomicIntegerArray` | 原子更新数组元素 | | **引用类型原子类** | `AtomicReference` | 原子更新对象引用 | | **原子更新属性** | `AtomicIntegerFieldUpdater` | 原子更新类的字段(需 volatile) | | **Adder 加法器** | `LongAdder`, `DoubleAdder` | 高并发场景的累加优化(分段 CAS)[^3] | | **积累器** | `LongAccumulator` | 支持自定义累加函数(如最大值) | #### **3. 核心原理:CAS 与优化** - **CAS 机制**(Compare and Swap): ```java // AtomicInteger 自增源码(简化) public final int getAndIncrement() { int prev, next; do { prev = get(); // 读取当前值 next = prev + 1; // 计算新值 } while (!compareAndSet(prev, next)); // CAS 自旋 return prev; } ``` - 硬件指令(如 `cmpxchg`)保证原子性[^2] - **高并发优化**: - `LongAdder` 采用**分段累加**:将值拆分为多个 Cell,分散竞争压力[^3] - 性能对比:高并发下 `LongAdder` > `AtomicLong` $$ \text{性能优势} \propto \frac{1}{\text{竞争线程数}} $$ #### **4. 作用与优势** | **场景** | **传统锁** | **原子类** | |--------------------|-------------------------------|-------------------------------| | **计数器递增** | `synchronized` 阻塞线程 | `AtomicInteger` 自旋无阻塞 | | **状态标志更新** | 需锁保护 | `AtomicBoolean` CAS 更新 | | **高并发统计** | 性能瓶颈 | `LongAdder` 分段累加[^3] | | **对象引用替换** | 复杂锁机制 | `AtomicReference` 单次 CAS | **核心优势**: - **避免阻塞**:无锁设计减少上下文切换 - **高性能**:低竞争场景比锁快 5-10 倍 - **简化代码**:无需显式同步(如 `volatile` + `synchronized`) #### **5. 使用注意事项** 1. **非通用替代品**: - 不重写 `equals()`/`hashCode()`,**不适合做哈希键**[^2] - 无 `byte`/`float` 专用类(可用 `AtomicInteger` 转换) 2. **ABA 问题**: - 使用 `AtomicStampedReference` 添加版本号解决 3. **自旋开销**: - 高竞争时 CPU 占用高(需评估场景) --- ### 相关问题 1. **`AtomicInteger` `synchronized` 在计数器场景的性能差异如何量化?** 2. **`LongAdder` 的分段累加策略如何避免 CAS 自旋开销?**[^3] 3. **如何用 `AtomicReference` 实现无锁栈(Stack)?** 4. **原子类能完全替代 `volatile` 关键字吗?为什么?** 5. **`AtomicIntegerFieldUpdater` 的使用限制是什么?**[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值