java常量和kotlin常量

  • java中使用final声明常量
  • kotlin中使用const val声明常量

常量在编译为字节码后会直接把调用常量的地方直接替换为常量值,示例如下:

public class ConstDemo {public static final String NAME = "Even";private static final int ID = 1001;static final int YEAR = 2024;public final int color = 255;public static int width = 100;public int height = 200;public static void main(String[] args) {System.out.println(NAME);System.out.println(NAME);System.out.println(ID);System.out.println(ID);System.out.println(YEAR);System.out.println(YEAR);ConstDemo demo = new ConstDemo();System.out.println(demo.color);System.out.println(demo.color);final int number = 9;System.out.println(number);System.out.println(number);System.out.println("--------------------------------");final int count;if (width > 100) {count = 1;} else {count = 2;}System.out.println(count);System.out.println(count);System.out.println(width);System.out.println(width);System.out.println(demo.height);System.out.println(demo.height);int weight = 99;System.out.println(weight);System.out.println(weight);}}

编译后得到class字节码,在IntelliJ中可以直接双击这个class字节码,它是自带反编译器,效果如下:

public class ConstDemo {public static final String NAME = "Even";private static final int ID = 1001;static final int YEAR = 2024;public final int color = 255;public static int width = 100;public int height = 200;public ConstDemo() {}public static void main(String[] args) {System.out.println("Even");System.out.println("Even");System.out.println(1001);System.out.println(1001);System.out.println(2024);System.out.println(2024);ConstDemo demo = new ConstDemo();PrintStream var10000 = System.out;Objects.requireNonNull(demo);var10000.println(255);var10000 = System.out;Objects.requireNonNull(demo);var10000.println(255);int number = true;System.out.println(9);System.out.println(9);System.out.println("--------------------------------");byte count;if (width > 100) {count = 1;} else {count = 2;}System.out.println(count);System.out.println(count);System.out.println(width);System.out.println(width);System.out.println(demo.height);System.out.println(demo.height);int weight = 99;System.out.println(weight);System.out.println(weight);}
}

如上代码,可以发现,只要是final修饰的变量在调用时直接被常量值替代了,有一个例外,就是在局部变量中声明的final int count;,它不是在声明时直接赋值的,而是经过一个if判断之后才赋值的,所以需要在运行时才能确定它的值是多少,所以在编译为字节码时调用该变量的地方没有被常量值替换,因为此时不知道它的值是多少。

另外也看到了一些有趣的地方,编译时编译器会有一些优化,比如int number = true;还能这样啊?没搞懂,它的final被去掉了,count中地final修饰符也被去掉了,而且类型变成了byte类型,编译器通过if中的判断得出值不是1就是2,用byte足已,所以改成了byte类型。

基于这个常量的特性,我们可以猜到,通过反射也是无法修改final类型的常量的,示例如下:

public class ConstDemo {public static final int age = 18;public static void main(String[] args) throws Exception {Field field = ConstDemo.class.getField("age");System.out.println("age = " + field.get(null));field.set(null, 30);System.out.println(age);}
}

运行结果如下:

age = 18
Exception in thread "main" java.lang.IllegalAccessException: Can not set static final int field ConstDemo.age to java.lang.Integerat java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)at java.base/jdk.internal.reflect.UnsafeQualifiedStaticIntegerFieldAccessorImpl.set(UnsafeQualifiedStaticIntegerFieldAccessorImpl.java:77)at java.base/java.lang.reflect.Field.set(Field.java:799)at ConstDemo.main(ConstDemo.java:9)

从这里也可以看出,为什么常量在编译为class字节码之后,调用它的地方已经被常量值所替换,为什么常量的声明语句还保留了,因为还是有可能会被用到的,比如我们通过反射读取该常量的值,这是需要在运行时才能完成的,无法在编译阶段就直接使用常量值替代的。

再来看一个Demo:

public class ConstDemo {public final int age = 18;public static final ConstDemo demo = new ConstDemo();public static void main(String[] args) throws Exception {System.out.println(demo);System.out.println(demo);System.out.println(demo.age);System.out.println(demo.age);}
}

编译为字节码后,再反编译结果如下:

public class ConstDemo {public final int age = 18;public static final ConstDemo demo = new ConstDemo();public ConstDemo() {}public static void main(String[] args) throws Exception {System.out.println(demo);System.out.println(demo);PrintStream var10000 = System.out;Objects.requireNonNull(demo);var10000.println(18);var10000 = System.out;Objects.requireNonNull(demo);var10000.println(18);}
}

可以看到声明为非原始类型的final常量在编译为字节码时无法使用常量值代替,因为它是一个对象,而对象的内存地址得在运行时才能确定,所以这种不应该叫常量的,所以,kotlin在这方面就做的比较好,表示一个变量不可改变用val,表示一个常量用const val,分得更加清楚,示例如下:

const val NAME = "Even"class ConstDemo {val width = 100var height = 200companion object {const val ID = 1001@JvmStaticfun main(args: Array<String>) {println(NAME)println(NAME)println(ID)println(ID)val demo = ConstDemo()println(demo.width)println(demo.height)}}}

可以看到,声明常量的地方只能是顶级属性或者companion object中,要查看反编译,如果直接在IntelliJ中找到class文件然后双击会发现反编译不了,我们可以这样查看:工具 > Kotlin > 显示Kotlin字节码 > 反编译,结果如下:

public final class ConstDemo {private final int width = 100;private int height = 200;public static final int ID = 1001;public final int getWidth() {return this.width;}public final int getHeight() {return this.height;}public final void setHeight(int var1) {this.height = var1;}public static final void main(@NotNull String[] args) {Intrinsics.checkNotNullParameter(args, "args");String var2 = "Even";System.out.println(var2);var2 = "Even";System.out.println(var2);short var4 = 1001;System.out.println(var4);var4 = 1001;System.out.println(var4);ConstDemo demo = new ConstDemo();int var3 = demo.getWidth();System.out.println(var3);var3 = demo.getHeight();System.out.println(var3);}
}public final class ConstDemoKt {@NotNullpublic static final String NAME = "Even";
}

在Kotlin中,常量只能是8大原始类型,不能是对象类型的,如下代码在编译器就报错了:
在这里插入图片描述
声明常量有什么好处?这里我想到之前写的一篇文章:https://blog.csdn.net/android_cai_niao/article/details/113571171

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海外云手机开辟企业跨境电商新道路

近几年&#xff0c;海外云手机为跨境电商、海外媒体引流、游戏行业等互联网领域注入了蓬勃活力。对于国内跨境电商而言&#xff0c;在亚马逊及其他平台上&#xff0c;短视频引流和社交电商营销成为最为有效的流量来源。如何通过海外云手机的助力&#xff0c;在新兴社交平台为企…

python二维高斯热力图绘制简单的思路代码

import numpy as np import matplotlib.pyplot as plt from scipy.ndimage import gaussian_filter import cv2# 生成一个示例图像 image_size 100 image np.zeros((image_size, image_size))# 在图像中心创建一个高亮区域 center_x, center_y image_size // 2, image_size …

【遥感专题系列】遥感影像信息提取之——人工目视解译

​遥感影像通过亮度值或像元值的高低差异&#xff08;反映地物的光谱信息&#xff09;及空间变化&#xff08;反映地物的空间信息&#xff09;来表示不同地物的差异&#xff0c;这是区分不同影像地物的物理基础。 ​人工解译是目前国内使用最多的一种影像提取方法&#xff0c;如…

力扣hot100 单词搜索 深度优先搜索 特殊字符判重

Problem: 79. 单词搜索 Code class Solution{int n, m;char[][] b;String word;int[] dx { 1, 0, -1, 0 };int[] dy { 0, 1, 0, -1 };public boolean exist(char[][] board, String word){b board;this.word word;n b.length;m b[0].length; // 以所有点作为起点来进行…

oracle rman duplicate创建测试库

1.在目标端建立参数文件&#xff0c;并启动到nomount&#xff0c;如果测试库的文件存放路径和生产不一致&#xff0c;配置db_file_name_convert和log_file_name_convert 2.拷贝生产的密码文件到目标端&#xff0c;配置生产到目标端的tnsnames 3.配置目标端的监听为静态监听&a…

生词本----Python实例练习

题目描述 背单词是英语学习中最基础的一环&#xff0c;不少学生在背诵单词的过程中会整理自己的生词本&#xff0c;以不断拓展自己的词汇量。本实例要求编写生词本程序&#xff0c;该程序需具备以下功能。 &#xff08;1&#xff09;查看生词列表功能&#xff1a;输出生词本中…

系统分析师-22年-下午题目

系统分析师-22年-下午题目 更多软考知识请访问 https://ruankao.blog.csdn.net/ 试题一必答&#xff0c;二、三、四、五题中任选其中两题作答 试题一 (25分) 说明 某软件公司拟开发一套博客系统&#xff0c;要求能够向用户提供一个便捷发布自已心得&#xff0c;及时有效的…

腾讯云SDK并发调用优化方案

目录 一、概述 二、 网关的使用 2.1 核心代码 三、腾讯云SDK依赖包的改造 一、概述 此网关主要用于协调腾讯云SDK调用的QPS消耗&#xff0c;使得多个腾讯云用户资源能得到最大限度的利用。避免直接使用腾讯云SDK 时&#xff0c;在较大并发情况下导致接口调用异常。网关的工…

Python与CAD系列高级篇(二十五)分类提取坐标到excel(补充圆半径、线长度、圆弧)

目录 0 简述1 分类提取坐标到excel2 结果展示0 简述 上一篇中介绍了:对点、直线、多段线、圆、样条曲线分类读取坐标并提取到excel。考虑到进一步提取图形信息,此篇补充对圆半径、线长度以及圆弧几何信息的提取。 1 分类提取坐标到excel 代码实现: import math import nump…

linux -- per-CPU变量

per-CPU变量 per-CPU变量是一种存在与每个CPU本地的变量&#xff0c;对于每一种per-CPU变量&#xff0c;每个CPU在本地都有一份它的副本。 per-CPU变量的优点 多处理器系统(smp)中无需考虑与其他处理器的竞争问题(并非绝对的)可以利用处理器本地的cache硬件&#xff0c;提高…

ClickHouse(24)ClickHouse集成mongodb表引擎详细解析

文章目录 MongoDB创建一张表用法示例 资料分享系列文章clickhouse系列文章 MongoDB MongoDB 引擎是只读表引擎&#xff0c;允许从远程 MongoDB 集合中读取数据(SELECT查询)。引擎只支持非嵌套的数据类型。不支持 INSERT 查询。 创建一张表 CREATE TABLE [IF NOT EXISTS] [db…

知识点积累系列(三)golang框架篇【持续更新】

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 知识点积累 系列文章的第三篇&#xff0c;记录日常学习中遇到的golang框架相关的知识点 1、gin框架相关 1.1.在gin中间件中直接return&#xff0c;相当于什么 在 Gin 中间件中直接使用 return 语句&#xff0…

Yolo v8 入门学习之采用 coco128 数据集进行图片检测测试

示例入门代码 from ultralytics import YOLO import cv2 import matplotlib.pyplot as plt import matplotlib.image as mpimgdef test():# Create a new YOLO model from scratchmodel YOLO(yolov8n.yaml)# Load a pretrained YOLO model (recommended for training)model …

Redis -- 开篇热身,常用的全局命令

目录 Redis重要文件 启动停止脚本 配置文件 持久化文件存储目录 核心命令 set get 全局命令 keys exists del expire ttl 过期策略是如何实现的 定时器 type 小结 Redis重要文件 启动停止脚本 /usr/bin/redis-benchmark &#xff1a; 用于对Redis做性能基准…

Python 因果推断(下)

六、2007-2009 年大衰退期间加拿大就业市场上白人女性名字的溢价 原文&#xff1a;causal-methods.github.io/Book/6%29_The_Premium_of_Having_a_White_Female_Name_in_the_Canadian_Job_Market_During_the_Great_Recession_2007_2009.html 译者&#xff1a;飞龙 协议&#xf…

AppSrv-DHCP(23国赛真题)

2023全国职业院校技能大赛网络系统管理赛项–模块B:服务部署(WindowServer2022) 文章目录 题目配置步骤安装和配置dhcp服务,为办公区域网络提供地址上网。创建地址池名为inside_pool,地址池范围:192.168.0.1-192.168.0.100。根据题目要求正确配置网关和dns信息。启动作用…

SpringCloud_学习笔记_1

SpringCloud01 1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 1.0.学习目标 了解微服务架构的优缺点 1.1.单体架构 单体架构&#xff…

开源电商系统

前言 做电商永不过时&#xff0c;但形式会不断变化。任何赚钱的事情大体都分为两大块&#xff1a;生产和销售。两者是并重的&#xff0c;首先要有好的产品&#xff0c;其次是做好推广运营和销售渠道建设。对于小微企业来说&#xff0c;前期如果能通过销售赚到第一桶金&#xf…

opencv学习 特征提取

内容来源于《opencv4应用开发入门、进阶与工程化实践》 图像金字塔 略 拉普拉斯金字塔 对输入图像进行reduce操作会生成不同分辨率的图像&#xff0c;对这些图像进行expand操作&#xff0c;然后使用reduce减去expand之后的结果&#xff0c;就会得到拉普拉斯金字塔图像。 …

【开源操作系统】上海道宁为您带来稳定、安全、开源和易用的操作系统——Ubuntu,为您的数字化生活保驾护航

Ubuntu是 源于非洲的一种传统价值观 意为“人性、关爱和共享” 这种价值观在 开源、稳定、安全、易用的 Ubuntu操作系统中 得到了完美的体现 除此之外&#xff0c;Ubuntu还具有 强大的安全性 它自带了诸多安全功能 如防火墙、加密文件系统等 可以有效地保护用户的隐私…