【Java从入门到放弃 之 final 关键字】

final 关键字

  • final 关键字
    • final 字段
    • final 函数列表中的参数
    • final 方法
    • final 类

final 关键字

Java中里面有final这个关键字,这个关键字总体上是用来表达” 不能被改变“ 这个意思的。我们使用这个关键字表达不能被改变,有两种使用场景,有三个使用位置。

使用场景

  1. 设计上就不允许改变的
  2. 为了效率不允许被改变

使用位置

  1. 字段
  2. 方法

我们将从使用位置着手,帮助大家了解final关键字的使用。

final 字段

很多时候,我们需要表达常量这个概念。我们都知道Java是面向对象的编程语言,在Java中一切都是对象Object;但是除此之外,Java还有8中基本数据类型。
所以final修饰的字段要么是8中基本数据类型,要么是Object。修饰基本类型的时候,代表的是修饰变量的值不能变化;修饰Object引用的时候,代表的是这个变量代表的引用不能改变(引用不能改变,但是引用指向的对象是可以改变的)

那既然是常量,不能被改变。那么我们怎么赋予其初始值呢?

  1. 直接初始化 : 可以在声明的时候直接给final变量赋值。这是最简单的方式,适用于你知道变量的确切值并且它不会改变的情况。
public class Example {
    public final int MAX_SIZE = 100;
}
  1. 构造器初始化 : 如果你需要根据不同的构造条件来设置final变量的值,那么可以在构造器中初始化它们。每个构造器都必须对所有的final实例变量进行初始化,否则编译器会报错。
public class Example {
    private final int maxSize;

    public Example(int size) {
        this.maxSize = size; // 必须在所有构造函数中初始化
    }
}

静态final变量 初始化也有两种

  1. 直接初始化
public class Example {
    public static final int MAX_SIZE = 100;
}
  1. 静态块初始化
public class Example {
    public static final int[] VALUES;

    static {
        // 更复杂的初始化逻辑
        VALUES = new int[3];
        VALUES[0] = 1;
        VALUES[1] = 2;
        VALUES[2] = 3;
    }
}

fianl修饰变量 - 代码案例

public class Final {

    private static final int VALUE_ONE = 1;
    private final int VALUE_TWO = 2;
    public static final int VALUE_THREE = 3;

    private final int int4 = Random.class.newInstance().nextInt(20);

    private Value v1 = new Value("1");
    private final Value v2 = new Value("2");
    private static final Value v3 = new Value("3");

    private final int[] array = {1, 2, 3, 4, 5};

    public Final() throws InstantiationException, IllegalAccessException {
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Final f = new Final();
        f.v2.value = "tes";
        f.v1 = new Value("new");
        //f.v2 = new Value("test2");
        for (int i = 0; i < f.array.length; i++) {
            f.array[i]++;
        }
        for (int i = 0; i < f.array.length; i++) {
            System.out.print(f.array[i]);
        }
    }
}

class Value {
    String value;

    public Value(String value) {
        this.value = value;
    }
}

final 函数列表中的参数

Java允许你用final 修饰参数列表中的形参,这个意味着,在这个函数中不能修改这个形参。如果这个形参代表的是基本参数类型,意味着函数体中不能修改参数值;如果修饰的是引用,代表我们不能修改引用。

public class Test8 {

    public static void main(String[] args) {
        System.out.println(add(1, 2));
        System.out.println(add(new Tmp1(1), new Tmp1(2)));
    }

    public static int add(final int a, final int b) {
        //a++;
        return a + b;
    }

    public static int add(final Tmp1 a, final Tmp1 b) {
        //a = new Tmp1("5");
        a.a = 5;
        b.a = 10;
        return a.a + b.a;
    }
}

class Tmp1 {
    int a;

    public Tmp1(int a) {
        this.a = a;
    }
}

final 方法

使用final修饰方法主要有两个方面的考虑

  1. 当一个方法被声明为final时,它不能被子类重写或覆盖,确保了父类的特定行为不会被改变,从而维护了父类的行为一致性。这对于那些你希望保持不变的核心功能特别有用。
  2. 编译器知道final方法不会被覆盖,因此可以在某些情况下进行内联优化。内联意味着直接将方法体插入到调用点,减少方法调用的开销,提升执行效率。

** final 和 private**
final关键字跟private关键字也有关系。任何类中的私有方法跟final差不多。因为我们没有获取私有方法的权限,这也就意味着,我们不能改变父类中的私有方法的实现。

private final 代码案例展示

public class Test9 {

    public static void main(String[] args) {
        OverRiddingBaseClass1 overRiddingBaseClass1 = new OverRiddingBaseClass1();
        overRiddingBaseClass1.f();
        overRiddingBaseClass1.f1();

//        BaseClass baseClass = overRiddingBaseClass1;
//        baseClass.f();
//        baseClass.f1();
//        OverRiddingBaseClass overRiddingBaseClass = overRiddingBaseClass1;
//        overRiddingBaseClass.f();
//        overRiddingBaseClass.f1();
    }
}

class BaseClass {

    private final void f() {
        System.out.println("BaseClass.f()");
    }

    private void f1() {
        System.out.println("BaseClass.f1()");
    }
}

class OverRiddingBaseClass extends BaseClass {

    private final void f() {
        System.out.println("OverRiddingBaseClass.f()");
    }

    private void f1() {
        System.out.println("OverRiddingBaseClass.f1()");
    }
}

class OverRiddingBaseClass1 extends OverRiddingBaseClass {
    public final void f() {
        System.out.println("OverRiddingBaseClass1.f()");
    }

    public void f1() {
        System.out.println("OverRiddingBaseClass1.f1()");
    }
}

Overriding 只会发生在父类非私有的方法中,上面代码案例中我们在最下面的子类把f()改成自己的实现,实际上这个方法是public,父类的是private;子类中的方法只是同名,不能算是父类的Overriding。

final 类

在Java中,使用final关键字修饰类(class)意味着该类不能被继承。这也就是说,任何试图创建此类子类的尝试都将导致编译错误。final类是不可扩展的,它提供了一些重要的好处,同时也带来了一定的限制。

  1. 防止继承:
  • 定义:当一个类被声明为final时,它不能作为其他类的父类。
  • 好处:确保了该类的行为和状态不会被改变或扩展,从而维护了类的完整性和一致性。
public final class FinalClass {
    // 类成员和方法
}
  1. 提高安全性
  • 防止恶意扩展:final类可以防止其他开发人员通过继承来修改类的行为,特别是在库或框架中公开的API中,这对于保护敏感逻辑或数据非常重要。
  • 避免意外破坏:减少了因继承带来的潜在错误风险,例如子类可能无意间改变了父类的关键行为。
  1. 促进编译器优化
  • 性能提升:由于final类的方法不能被重写,编译器可以在某些情况下对这些方法进行内联调用等优化操作,从而提高程序执行效率。
  • 静态绑定:对于final类的方法调用,编译器可以直接确定要调用的方法版本,无需在运行时动态查找最合适的版本。
  1. 表达设计意图
  • 清晰的设计语义:通过将类声明为final,开发者明确表达了不允许对该类进行任何扩展的设计意图。这有助于其他开发人员理解代码库中的不可变规则和限制条件。
  • 文档化:final关键字起到了一种自我文档的作用,告诉其他程序员哪些类是固定的,哪些是可以自由扩展的。
  1. 支持不可变对象
  • 构建不可变类:为了实现不可变性,通常会将所有方法都设为final,并且让类本身也成为final。这样可以确保一旦对象创建后其状态不会发生变化,有助于构建线程安全的对象,因为在多线程环境中,不可变对象天生就是线程安全的。
  1. 简化调试和维护
  • 减少复杂度:当类不能被继承时,追踪其行为变得更为简单,因为你不需要考虑不同子类中可能存在的各种重写版本。
  • 降低维护成本:由于final类的行为是固定的,所以在进行代码审查或维护时,可以更放心地依赖这些类的一致性表现,减少了需要考虑的变量和可能性。
  1. 限制
  • 灵活性降低:final类不能被继承,这意味着如果以后需要扩展类的功能,必须通过组合或其他设计模式来实现,而不是直接继承。
  • 代码复用受限:因为不能继承,所以不能利用继承机制来复用final类中的代码。

final修饰class使用场景

  • 核心类库:如Java标准库中的String、Integer等包装类都是final的,以保证它们的安全性和一致性。
  • 工具类:当类主要包含静态方法,并且不打算被实例化时,可以将其声明为final,如Math类。
  • 安全敏感类:涉及敏感信息处理或系统资源管理的类应该考虑设为final,以防止未经授权的修改。
  • 不可变类:为了实现线程安全和不可变性,类及其成员应尽可能设为final。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/949936.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计算机视觉】单目深度估计模型-Depth Anything-V2

概述 本篇将简单介绍Depth Anything V2单目深度估计模型&#xff0c;该模型旨在解决现有的深度估计模型在处理复杂场景、透明或反射物体时的性能限制。与前一代模型相比&#xff0c;V2版本通过采用合成图像训练、增加教师模型容量&#xff0c;并利用大规模伪标签现实数据进行学…

jenkins入门12-- 权限管理

Jenkins的权限管理 由于jenkins默认的权限管理体系不支持用户组或角色的配置&#xff0c;因此需要安装第三发插件来支持角色的配置&#xff0c;我们使用Role-based Authorization Strategy 插件 只有项目读权限 只有某个项目执行权限

【Microi吾码】开源力量赋能低代码创新,重塑软件开发生态格局

我的个人主页 文章专栏&#xff1a;Microi吾码 一、引言 在当今数字化浪潮汹涌澎湃的时代&#xff0c;软件开发的需求呈现出爆发式增长。企业为了在激烈的市场竞争中脱颖而出&#xff0c;不断寻求创新的解决方案以加速数字化转型。传统的软件开发方式往往面临着开发周期长、技…

HTB:Bank[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 提取出靶机TCP开放端口 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 使用curl对域名进行访问…

操作手册:集成钉钉审批实例消息监听配置

此文档将记录在慧集通平台怎么实现钉钉审批实例结束或发起或取消时&#xff0c;能够实时的将对应的实例数据抓取出来送入第三方系统 集成平台配置 1、配置中心库&#xff0c;存储钉钉发送的消息&#xff0c;可以忽略&#xff0c;若不配置&#xff0c;则钉钉的消息将不再记录到…

【C++】B2118 验证子串

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目概述题目描述输入格式输出格式输入输出样例样例 1样例 2 题目提示 &#x1f4af;解决方案分析初步分析与思路 &#x1f4af;我的代码实现与分析代码回顾实现逻辑与优缺…

68.基于SpringBoot + Vue实现的前后端分离-心灵治愈交流平台系统(项目 + 论文PPT)

项目介绍 本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述心灵治愈交流平台的当前背景以及系统开发的目的&#xff0c;后续章节将严格按照软件开发流程&#xff0c;对系统进…

【分布式缓存】一致性Hash原理剖析,一致性Hash与Hash的区别(详解)

文章目录 Hash算法Hash算法的缺陷一致性Hash算法一致性Hash存储规则一致性Hash解决Hash的缺陷问题一致性Hash的偏斜问题一致性哈希在实际中的应用总结 更多相关内容可查看 假设有一个场景&#xff1a;有三万张图片&#xff0c;有三台服务器S0&#xff0c;S1&#xff0c;S2 要求…

Clisoft SOS与CAD系统集成

Clisoft SOS与CAD系统集成 以下内容大部分来自官方文档&#xff0c;目前只用到与Cadence Virtuoso集成&#xff0c;其他还未用到&#xff0c;如有问题或相关建议&#xff0c;可以留言。 与Keysight ADS集成 更新SOS客户端配置文件sos.cfg&#xff0c;以包含支持ADS的模板&am…

Java-数据结构-链表-高频面试题(1)

在上一篇文章中&#xff0c;我们学习了链表中的"单向链表"&#xff0c;但学可不代表就是学会了&#xff0c;能够运用链表的地方比比皆是&#xff0c;解题方法也是层出不穷&#xff0c;今天就让我们巩固一下"单向链表"的知识吧~ 第一题&#xff1a;相交链表…

JVM实战—OOM的定位和解决

1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是&#xff1a;建立一套监控平台&#xff0c;比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台&#xff0c;就可以接入系统异常的监控和报警&#xff0c;可以设置当系统出现OOM异常&…

照片做成图书小程序开发制作介绍

照片做成图书小程序系统&#xff0c;主要是让用户直接通过小程序选择需要做成书的类型和照片排版布局模板&#xff0c;以及上传照片的数量。照片上传完成后&#xff0c;生成模板图片样式进行预览或编辑修改。修改完成全部保存。保存后生成完整的照片书进行预览没问题&#xff0…

云商城--业务+架构学习和环境准备

云商城业务架构学习和环境准备 B2B&#xff1a;Business to Business&#xff0c;交易双方的身份都是商家&#xff0c;也就是商家将商品卖给商家&#xff0c;类似采购、批发类购物&#xff0c;国内代表性网站阿里巴巴批发网 C2C&#xff1a;Customer to Customer&#xff0c;…

Elasticsearch:Lucene 2024 年回顾

作者&#xff1a;来自 Elastic Chris Hegarty 2024 年对于 Apache Lucene 来说又是重要的一年。在本篇博文中&#xff0c;我们将探讨主要亮点。 Apache Lucene 在 2024 年表现出色&#xff0c;发布了许多版本&#xff0c;包括三年来的首次重大更新&#xff0c;其中包含令人兴奋…

基于LabVIEW的BeamGage自动化接口应用

设置 National Instruments LabVIEW可执行程序需要被配置为使用.NET 4框架。.NET允许自定义可执行程序的运行方式。可通过以下方式实现&#xff1a; 在LabVIEW安装目录中创建一个名为LabVIEW.exe.config的文本文件&#xff08;例如&#xff1a;C:\Program Files\National Ins…

卸载干净 IDEA(图文讲解)

目录 1、卸载 IDEA 程序 2、注册表清理 3、残留清理 1、卸载 IDEA 程序 点击屏幕左下角 Windows 图标 -> 设置-控制面板->intellij idea 勾选第一栏 Delete IntelliJ IDEA 2022.2 caches and local history&#xff0c;表示同时删除 IDEA 本地缓存以及历史。 Delete I…

李宏毅机器学习课程笔记02 | 机器学习任务攻略General Guide

第一步&#xff1a;分析loss on training data 先检查在训练数据上模型是否很好的学习 情况1&#xff1a;如果在训练集上&#xff0c;loss很大&#xff0c;说明在训练资料上没有训练好 可能性1&#xff1a;设置的模型太简单了&#xff0c;模型存在model bias模型偏差&#x…

【C++】19.多态

文章目录 1. 多态的概念2. 多态的定义及实现2.1 多态的构成条件2.1.1 实现多态还有两个必须重要条件&#xff1a;2.1.2 虚函数 (Virtual Function)定义&#xff1a;特性&#xff1a;示例代码&#xff1a;代码分析1. 类定义部分2. 主函数部分运行结果 重点讲解1. 虚函数的作用2.…

光伏仿真与设计系统应用架构深度剖析

在光伏产业蓬勃发展的时代背景下&#xff0c;绿虫光伏仿真与设计系统成为推动其高效发展的核心力量。其应用架构涵盖多个关键步骤&#xff0c;每个环节都紧密相扣&#xff0c;共同构建起精准且高效的设计体系。 气象分析作为开篇之笔&#xff0c;起着基石般的重要作用。系统全…

进程间通讯

简介&#xff1a; 进程间通讯方式有&#xff1a; 1.内存映射&#xff08;mmap&#xff09;&#xff1a; 使用mmap函数将磁盘空间映射到内存 2.管道 3.信号 4.套接字&#xff08;socket&#xff09; 5.信号机制 通过进程中kill函数&#xff0c;去给另一个函数发送信号&a…