java常量和kotlin常量

news2024/11/22 19:54:44
  • 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.Integer
	at 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 = 100
    var height = 200

    companion object {
        const val ID = 1001

        @JvmStatic
        fun 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 {
   @NotNull
   public static final String NAME = "Even";
}

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

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

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

相关文章

让MySQL和Redis数据保持一致的4种策略

1 前言 先阐明一下 MySQL 和 Redis 的关系&#xff1a;MySQL 是数据库&#xff0c;用来持久化数据&#xff0c;一定程度上保证数据的可靠性&#xff1b;Redis 是用来当缓存&#xff0c;用来提升数据访问的性能。 关于如何保证 MySQL 和 Redis 中的数据一致&#xff08;即缓存…

leetcode常见错误

1 runtime error: load of null pointer of type ‘std::_Bit_type‘ (aka ‘unsigned long‘) (stl_bvector&#xff09; 力扣&#xff1a;runtime error: load of null pointer of type ‘std::_Bit_type‘ (aka ‘unsigned long‘) (stl_bvector&#xff09;_runtime error…

Threejs API——获得场景中的所有对象

文章目录 获取的对象加载模型1. 网格模型 Mesh2. 基本对象容器 Group3. 基类 Object3D获取的对象 加载模型 //加载gltf模型loadgltf() {let loader = new

VUE3+elementPlus 之 Form表单校验器 之 字符长度校验

需求&#xff1a;校验字符长度&#xff0c;超过后仍可输入&#xff0c;error提示录入字符数与限制字符数 校验字符长度&#xff1a; /*** 检验文字输入区的长度* param {*} rule 输入框的rule 对象&#xff0c;field&#xff1a;字段名称* param {*} value …

Python爬虫:XPath基本语法

XPath&#xff08;XML Path Language&#xff09;是一种用于在XML文档中定位元素的语言。它使用路径表达式来选择节点或节点集&#xff0c;类似于文件系统中的路径表达式。 不啰嗦&#xff0c;讲究使用&#xff0c;直接上案例。 导入 pip3 install lxmlfrom lxml import etr…

如何有效避免市场恐慌性抛售?

布雷特斯坦伯格是一位备受尊敬的交易心理导师&#xff0c;曾担任华尔街多家顶级培训机构的心理导师&#xff0c;指导交易员们如何应对心理挑战。作为一名心理学教授和资深交易员&#xff0c;他对交易心理的理解远超常人。人们普遍认为&#xff0c;要想在交易领域取得成功&#…

年底特殊时期外贸装柜多花点心思

如果可以&#xff0c;尽量不要在工厂快要放假的时候安排装柜了&#xff0c;一个是人手不够&#xff0c;一个是容易漏货&#xff0c;还有就是柜子不好定。 看到有人说自己客户收到货的时候比预期晚了两个星期&#xff0c;一直延误&#xff0c;已经比原来要计划开业的时间推迟&a…

Flink实战四_TableAPISQL

接上文&#xff1a;Flink实战三_时间语义 1、Table API和SQL是什么&#xff1f; 接下来理解下Flink的整个客户端API体系&#xff0c;Flink为流式/批量处理应用程序提供了不同级别的抽象&#xff1a; 这四层API是一个依次向上支撑的关系。 Flink API 最底层的抽象就是有状态实…

Linux Archcraft结合内网穿透实现SSH远程连接

文章目录 1. 本地SSH连接测试2. Archcraft安装Cpolar3. 配置 SSH公网地址4. 公网远程SSH连接5. 固定SSH公网地址6. SSH固定地址连接7. 结语 Archcraft是一个基于Arch Linux的Linux发行版&#xff0c;它使用最简主义的窗口管理器而不是功能齐全的桌面环境来提供图形化用户界面。…

5款简单好用的软件,总有一款适合你

​ 今天为大家推荐五款不常见但好用的win10软件&#xff0c;它们都有着各自的特色和优势&#xff0c;相信你会喜欢的。 1.文件传输——FileZilla ​ FileZilla是一款开源的FTP软件&#xff0c;支持FTP、SFTP和FTPS协议&#xff0c;可以实现文件的上传和下载。FileZilla具有多…

远程访问@HttpExchange

提示&#xff1a;这是SpringBoot3以上的新特性。 远程访问HttpExchange 一、webClient二、Http 服务接口的方法定义三、声明式 HTTP 远程服务1.组合使用注解2.使用单个注解3.定制 HTTP 请求服务 四、总结1.部分方法过时2.过时的方法详解 远程访问是开发的常用技术&#xff0c;一…

KVM-安装-使用-迁移

一. KVM安装 1. 基础安装 # 下载源 curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo# 安装基础软件 yum -y install tree vim wget bash-completion bash-completion-extras lrzsz net-tools sysstat iotop iftop htop unzip nc nmap …

Qt关于qss文件的添加使用

把ui设计得更加的养眼&#xff0c;肯定需要对控件的属性进行设置&#xff0c;qt中就是关于qss文件的使用。 那么如何创建和添加qss文件呢 1.新建一个文本文件的txt 2.将文本文件的后缀改为qss&#xff08;类比html&#xff09; 3.放置到项目的资源文件夹下 4.添加资源文件 5.在…

基于Kubernetes的微服务架构,你学废了吗?

至于服务网关&#xff0c;虽然保留了 Zuul&#xff0c;但没有采用 Kubernetes 的 Ingress 来替代。这里有两个主要考虑因素&#xff1a;首先&#xff0c;Ingress Controller 并非 Kubernetes 的内置组件&#xff0c;有多种可选方案&#xff08;例如 KONG、Nginx、Haproxy 等&am…

asdf安装不同版本的nodejs和yarn和pnpm

安装asdf 安装nodejs nodejs版本 目前项目中常用的是14、16和18 安装插件 asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git asdf plugin-add yarn https://github.com/twuni/asdf-yarn.git可以查看获取所有的nodejs版本 asdf list all nodejs有很多找…

Wireshark网络协议分析 - TCP协议

在我的博客阅读本文 文章目录 1. 基础2. 实战2.1. 用Go写一个简单的TCP服务器与客户端2.2. Wireshark抓包分析2.3. 限制数据包的大小——MSS与MTU2.4. 保证TCP的有序传输——Seq&#xff0c;Len与Ack2.5. TCP头标志位——URG&#xff0c;ACK&#xff0c;PSH&#xff0c;RST&…

【前端素材】bootstrap3 实现地产置业公司source网页设计

一、需求分析 地产置业公司的网页通常是该公司的官方网站&#xff0c;旨在向访问者提供相关信息和服务。这些网页通常具有以下功能&#xff1a; 公司介绍&#xff1a;网页通常包含有关公司背景、历史、核心价值观和使命等方面的信息。此部分帮助访问者了解公司的身份和目标。 …

visual studio2022专业版安装步骤

目录 一、Visual studio下载二、创建C#项目——Hello World三、专业版秘钥激活 一、Visual studio下载 首先进入下载官网 先下载2022专业版&#xff0c;等等后面还需要选环境 我勾选了以下几个和c#开发有关的&#xff0c;后面缺什么还可以再安装所有以少勾了问题也不大 然后…

solidworks 焊接型材库

型材库中有大部分型材 H型钢有49种 八角钢有40种 扁钢有60种 不等边钢有84种 槽钢有41种 也可以按照自己需要的去添加 下载地址https://download.csdn.net/download/jintaihu/19347986

《金融电子化》昆仑银行在应用性能监控(APM)平台的实践与探索

《金融电子化》昆仑银行在应用性能监控&#xff08;APM&#xff09;平台的实践与探索 中国人民银行印发的《金融科技发展规划&#xff08;2022-2025年&#xff09;》是对金融科技发展的重要引领。规划强调了金融科技在推动金融行业现代化转型、提升金融服务效率和风险防控水平…