java中的编译时常量与运行时常量
常量是程序运行期间恒定不变的量,许多程序设计语言都有某种方式,向编译器告知一块数据是恒定不变的,例如C++中的const和Java中的final。
根据编译器的不同行为,常量又分为编译时常量和运行时常量,其实编译时常量肯定就是运行时常量,只是编译时常量在编译的时候就被执行计算,并带入到程序中一切可能用到它的计算式中。
以Java为例,static final int a = 1将是一个编译时常量,编译后的符号表中将找不到a,所有对a的引用都被替换成了1。
而static final int b = “”.length()将是一个运行时常量。测试代码如下:
class Test {
public static final int a = 10;
public static final int b = "test".length();
static {
System.out.println("Class Test Was Loaded !");
}
}
public class CompilConstant {
public static void main(String[] args) {
System.out.println(Test.a);
System.out.println(Test.b);
}
}
输出:
10
Class Test Was Loaded !
4
即:
1. a被作为编译期全局常量,并不依赖于类,而b作为运行期的全局常量,其值还是依赖于类的。
2. 编译时常量在编译时就可以确定值,上例中的a可以确定值,但是b在编译期是不可能确定值的。
3. 由于编译时常量不依赖于类,所以对编译时常量的访问不会引发类的初始化。
测试:
//System.out.println(Test.b);//注释掉该条代码
执行
javac CompilConstant.java
del Test.class
也就是把编译生成的Test.class 删除,并执行java CompilConstant,输出:
10
执行反汇编:
javap -v CompilConstant
D:\N3verL4nd\Desktop>javap -v CompilConstant
Classfile /D:/N3verL4nd/Desktop/CompilConstant.class
Last modified 2017-10-21; size 440 bytes
MD5 checksum faf8cf7e41ff58ae190d78fbb7e7635c
Compiled from "CompilConstant.java"
public class CompilConstant
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#16 // java/lang/Object."<init>":()V
#2 = Fieldref #17.#18 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Class #19 // Test
#4 = Methodref #20.#21 // java/io/PrintStream.println:(I)V
#5 = Fieldref #3.#22 // Test.c:I
#6 = Class #23 // CompilConstant
#7 = Class #24 // java/lang/Object
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 main
#13 = Utf8 ([Ljava/lang/String;)V
#14 = Utf8 SourceFile
#15 = Utf8 CompilConstant.java
#16 = NameAndType #8:#9 // "<init>":()V
#17 = Class #25 // java/lang/System
#18 = NameAndType #26:#27 // out:Ljava/io/PrintStream;
#19 = Utf8 Test
#20 = Class #28 // java/io/PrintStream
#21 = NameAndType #29:#30 // println:(I)V
#22 = NameAndType #31:#32 // b:I
#23 = Utf8 CompilConstant
#24 = Utf8 java/lang/Object
#25 = Utf8 java/lang/System
#26 = Utf8 out
#27 = Utf8 Ljava/io/PrintStream;
#28 = Utf8 java/io/PrintStream
#29 = Utf8 println
#30 = Utf8 (I)V
#31 = Utf8 b
#32 = Utf8 I
{
public CompilConstant();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 9: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: getstatic #5 // Field Test.b:I
14: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
17: return
LineNumberTable:
line 11: 0
line 12: 8
line 13: 17
}
SourceFile: "CompilConstant.java"
D:\N3verL4nd\Desktop>
可见,对于Test.a的输出直接把bipush 10 10压入栈中。
java中的编译时常量与运行时常量的更多相关文章
- java中最常见的几种运行时异常,你get了吗?
NullPointerException (空指针异常) ClassCastException (类型强制转换异常) NumberFormatException (数字格式异常) NegativeAr ...
- Java 9 揭秘(7. 创建自定义运行时映像)
Tips 做一个终身学习的人. 在第一章节中,主要介绍以下内容: 什么是自定义运行时映像和JIMAGE格式 如何使用jlink工具创建自定义的运行时映像 如何指定命令名称来运行存储在自定义映像中的应用 ...
- Java内存区域与内存溢出异常---运行时数据区域
运行时数据区域 Java虚拟机所管理的内存将会包括以下几个运行时数据区域 线程私有区域 1.程序计数器 程序计数器记录的是当前正在执行的虚拟机字节码指令所在的地址.在虚拟机的概念模型中,字节码解释 ...
- Java中的栈,堆,方法区和常量池
要说Java中的栈,堆,方法区和常量池就要提到HotSpot,HotSpot是Sun JDK 和 Open JDK中所带的虚拟机. (Sun JDK 和 Open JDK除了注释不同,代码实现基本上是 ...
- java中使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
java中使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 是引用对象的地址值不能变,引用变量所指向的对象的内容是可以改变. final变量永远指向这个对象,是一个常量指针,而 ...
- Stack overflow 编译能通过,运行时出现Stack overflow
Stack overflow 编译能通过,运行时出现Stack overflow 大家都知道,Windows程序的内存机制大概是这样的,全局变量(局部的静态变量本质也属于此范围)存储于堆内存,该段内存 ...
- Java 中的编译期常量是什么?使用它又什么风险?
公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里 的 public 可选的.实际上这些变量在编译时会被替换掉,因为编译器知道这些 变量的值,并且知道这些变 ...
- java多态的向上转型与向下转型(与编译时类型与运行时类型有关)
1.编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定. 当编译时类型和运行时类型不一致时,就会出现所谓的多态. 因为子类是一个特殊的父类,因此java允许把一个子类对象直接 ...
- 读书笔记:深入理解java虚拟机(一)虚拟机的运行时的数据区域
最近在看深入了解java虚拟机第一版(周志明著),特此写读书笔记,整理其中重要的东西和自己的理解. ”java与c++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却 ...
随机推荐
- Hbase数据库
1.简介 HBase从诞生至今将近10年,在apache基金会的孵化下,已经变成一个非常成熟的项目,也有许多不同的公司支持着许多不同的分支版本,如cloudra等等. HBase不同于一般的关 ...
- 【java】内部类
内部类:将一个类定义在另一个类里.对里面的那个类就是内部类. 访问特点: 1.内部类可以直接访问外部类的成员,包括私有.之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部的引用,格式 外部 ...
- Verilog编码规范与时序收敛
Verilog编码规范与时序收敛 没有优先级的时候,尽量用case 时钟选择
- golang操作memcached 转自https://blog.csdn.net/weixin_37696997/article/details/78760397
go使用memcached需要第三方的驱动库,这里有一个库是memcached作者亲自实现的,代码质量效率肯定会有保障 1:安装 go get github.com/bradfitz/gomemcac ...
- Laravel5笔记--路由
路由:简单讲就是定义URL请求转向某个业务逻辑(一般是控制器方法)的方法. 1.路由定义文件: /routes/web.php //定义web访问的路由 /routes/api.php // ...
- python用字符串调用当前模块内的函数
eval(字符串)() vars()[字符串]() 例如:
- Java Exception 和Error
(事先声明:该文章并非完全是我自己的产出,更多的是我个人在看到资料后通过理解并记录下来,作为自己阅读后的一个笔记:我现在试图对自己多年工作中的知识点做一个回顾,希望能融会贯通) (此文参考<Ja ...
- [转][C#]服务安装卸载命令
c:\windows\microsoft.net\Framework\v2.0.50727\installutil.exe [/u] X:\服务.exe
- (转)通过注册表修改VC6.0的字体
出处:http://www.cnblogs.com/PocketZ 在VC6.0下更改字体,我们一般通过菜单-Tools-Options-Format来更改 但在我的win7 64位系统下这一选项下的 ...
- bitmap--Bitmap详解与Bitmap的内存优化
一.Bitmap: Bitmap是Android系统中的图像处理的最重要类之一.用它可以获取图像文件信息,进行图像剪切.旋转.缩放等操作,并可以指定格式保存图像文件. 常用方法: public voi ...