当前位置:首页 » 编程软件 » java编译常量折叠

java编译常量折叠

发布时间: 2023-05-05 06:14:21

① String a="a"; String b="b"; a=a+b; 这里共创建了几个对象

这里共创建了3个对象。

"a"+"b"+"c"在编译期已经常量折叠为"abc",变量a获得是"abc"。

甲骨文jdk(1.7),javac会进行常量折叠,全字面量字符串相加是可以折叠为一个字面常量,而且是进入常量池的。这个问题涉及到了字符串常量池和字符串拼接。

只创建了一个对象,在字符串池只会有一个对象。因为它是一行定义的对象,编译时只会初始化一次字符串缓冲池的数据。如果是 String a="a";String b="b";String c="c";String d=a+b+c;这里就创建了4个对象。

(1)java编译常量折叠扩展阅读

String 对象的实现:

String 对象的创建方式

1、通过字符串常量的方式

String str= "pingtouge"的形式,使用这种形式创建字符串时, JVM 会在字符串常量池中先检查是否存在该对象,如果存在,返回该对象的引用地址,如果不存在,则在字符串常量池中创建该字符串对象并且返回引用。

使用这种方式创建的好处是:避免了相同值的字符串重复创建,节约了内存

2、String()构造函数的方式

String str = new String("pingtouge")的形式,使用这种方式创建字符串对象过程就比较复杂,分成两个阶段,首先在编译时,字符串pingtouge会被加入到常量结构中,类加载时候就会在常量池中创建该字符串。

然后就是在调用new()时,JVM 将会调用String的构造函数,同时引用常量池中的pingtouge字符串,在堆内存中创建一个String对象并且返回堆中的引用地址。

② JAVA代码编译


publicclassTest{
publicstaticvoidmain(Stringargs[]){
带亩Squaresquare=newSquare(4);
doublearea=square.area();
System.out.println("面积为州行蠢:"+area);
}
}

interfaceIShape{
publicdoublearea();
}

classSquareimplementsIShape{
privatedoublea;

publicSquare(doublea){
this.a=a;
}

@Override
publicdoublearea()册陪{
returna*a;
}
}

③ 为什么我的这个程序的字符串“+拼接”比StringBuilder的“append拼接”快呢

这种结果是正常的,因为你的循环数量特别大,大部分时间分配给了循环,当使用+的时候sbbb.append("1" + "aaaaaa" + "2");,括号中的静态字符串会相加(底层是使冲唯用StringBuilder的append()方法实现的),相加之后,在字符串的静态缓存区就会存在一个新的静态字符串“1aaaaaa2”,当下次循环再调用这个语句:sbbb.append("1" + "aaaaaa" + "2")时,String的优陵锋化机制已经记住了这个表达式("1" + "aaaaaa" + "2"),会把这个表达式直接转换为静态缓存区中的"1aaaaaa2",
也就是说从第二次循环开始就做了这样的操作:sbbb.append("1aaaaaa2");,而不是重新去计算("1" + "aaaaaa" + "2")的结果。下面的语句sbb.append("1"); sbb.append("aaaaaa"); sbb.append("2");从第二次循环开始,每次还是调用三次append()方散汪培法,而上面的刚才说了,从第二次开始只是调用了一次append()方法而已。
另外,在使用StringBuilder的时候最好指定初始容量,一般有个默认初始容量,如果不指定,比如你要操作的长度为256,而初始长度只是16,它就会扩大缓存区,影响效率,所以可以预知字符串大小时,最好指定初始容量,以便提升效率,比如StringBuilder sb = new StringBuilder(256);

④ java如何优化编译呢

#java编译器对`String常量表达式`的优化:
- 1.String+String 可以被编译器识别为常量表达
String a="ab" ;
String b="a"+"b";//编译后:b="ab"
System.out.println(a==b);//true
分析:
编译器将"a"+"b"当做常量表达式,在编译时期进行优化,直接取"ab". 在运行时期
并没有创建新的对象,而是从jvm字符串常量池中获取之前已经存在的"ab"对象.

- 2.String+基本类型 可以被编译器识别为常量表达式

String a="a1";
String b="a"+1; //"a1"
String c="a"+true;//"atrue"
String d="a"+3.14;//"a3.14"

#java编译器对`常量`优化:
* 它是编译时的一项优化技术,将代码的常量计算在编译期完成,节约了运行时的计算量.

1.常量替换
//编译前:
final int x=10;
int y=x;

//编译后
int x=10;
int y=10;//编译时,常量替换了

2.数学恒等式的模式匹配替换

//编译前:
int x=10+10;

//编译后
int x=20;//编译时,模式匹配替换了

3.常量折叠

//编译前:
boolean flag=true||(a || b && c);

//编译后
boolean flag=true;//编译时,常量折叠了

⑤ javac编译后文件内容变化

当使用javac编译器编译Java源代码时,会产生一个字节码文件,它包含了Java虚拟机(JVM)可以理解的指令。字节码文件的内容是由Java源代码编译而来的,它们是由一系列指令组成的,这些指令描述了Java虚拟机如何执行Java程序。字节码文件的内容可以被用来描述Java程序的行为,这些指令可以用来控制Java程序的执行,以及它们如何处理数据。字节码文件还可以包含元数据,这些元数据可以用来描述Java程序的结构,以及它们如何与其他程序交互。字节码文件的内容可以被用来描述Java程序的行为,这些指令可以用来控制Java程序的执行,以及它们如何处理数据。字节码文件还可以包含元数据,这些元数据可以用来描述Java程序的结陆棚则构,以及它们如和皮何与其他程序交互。此外,字节码文件还可以包含一些额外的信息,例如类型信息,变量名称和方法名称等。总之,字节码文件的内容可以用来描述Java程序的行为,以及它们如何处理数据和与其他早棚程序交互。

⑥ javashort怎么-1

注:如未特别说明,Java语言规范 jls 均基于JDK8,使用环境是 eclipse4.5 + win10 + JDK 8
本篇的知识点,主要是涉及到 Java 中一些比较答橡雹常见的默认窄化处理(Java编译器自动添加的),这里将从一个问题开始,据说这也是一道常见的笔试题/面试题:

为什么 short i = 1; i += 1; 可以正确编译运行而 short i = 1; i = i + 1; 会出现编译错误?

其他说法:都放在一起编译会出现有什么结果,哪一行报错?为什么?

笔者注:其实这其中会涉及到一些编译优化和底层的知识,限于知识面,本篇不涉及,如有需要,可自行搜索。

本文的目录结构如下:

1、结论

关于开篇提出的问题,这里先直接给出结论:

Java语言规范规定基础数据类型运算默认使用32位精度的int类型

只要是对基本类型做窄化处理的,例如 long -> int -> short -> char,都需要做强制转换,有些是Java编译器默认添加的,有的则是代码中显式做强制转换的。

short i = 1; i += 1;可以正确编译运行是因为Java编译器自己添加了强制窄化处理,即对于任何的T a; X b; a += b;等价于T a; X b; a = (T) (a + b);Java编译器会默认做这个显式强制转换(尽管有时候会出现精度问题,例如 b 是 float 、 double 类型,强烈建议不要有这样的操作)。前面的i += 1其实就等价于i = (int) (i + 1),即便将数字1换成是double类型的1.0D也是如此。

short i = 1; i = i + 1;编译不通过的原因就很明显了:无论是代码中,还是Java编译器,都没有做强制转换,int 类型直接赋给 short ,因此编译出错。

对于常量(数字常量、常量表达式、final常量等),Java编译器同样也可以做默认的强制类型转换,只要常量在对应清帆的数据范围内即可。

2、详如歼解

接下来讲详细分析为什么 short i = 1; i += 1; 可以正确编译而 short i = 1; i = i + 1; 则会编译失败。先列一下搜出来的一些令人眼前一亮(or 困惑)的代码

public static voidmain(String[] args) {//注:short ∈ [-32768, 32767]

{/** 1、对于 +=, -=, *=, /=, Java编译器默认会添加强制类型转换,

* 即 T a; X b; a += b; 等价于 T a; X b; a = (T) (a + b);*/

//0是int类型的常量,且在short范围内,被Java编译器默认强制转换的

short i = 0;

i+= 1; //等价于 i = (short) (i + 1);

System.out.println("[xin01] i=" + i); //输出结果: 1

i = (short) (i + 1);

System.out.println("[xin02] i=" + i); //输出结果: 2

/** 下面这2行都会有编译报错提示:

* Exception in thread "main" java.lang.Error: Unresolved compilation problem:

* Type mismatch: cannot convert from int to short

* [注]错误: 不兼容的类型: 从int转换到short可能会有损失

* Eclipse 也会有提示: Type mismatch: cannot convert from int to short*/

//i = i + 1;//i = 32768;

i= 0;

i+= 32768; //等价于 i = (short) (i + 32768); 下同

System.out.println("[xin03] i=" + i); //输出结果: -32768

i += -32768;

System.out.println("[xin04] i=" + i); //输出结果: 0

i= 0;long j = 32768;

i+=j;

System.out.println("[xin05] i=" + i); //输出结果: -32768

i= 0;float f = 1.23F;

i+=f;

System.out.println("[xin06] i=" + i); //(小数位截断)输出结果: 1

i= 0;double d = 4.56D;

i+=d;

System.out.println("[xin07] i=" + i); //(小数位截断)输出结果: 4

i= 10;

i*= 3.14D;

System.out.println("[xin08] i=" + i); //输出结果: 31

i= 100;

i/= 2.5D;

System.out.println("[xin09] i=" + i); //输出结果: 40

}

{/** 2、常量表达式和编译器优化: 常量折叠*/

//2 * 16383 = 32766//(-2) * 16384 = -32768//都在 short 范围内,常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换

short i = 2 * 16383; //等价于 short i = (short) (2 * 16383);

short j = (-2) * 16384;//2 * 16384 = 32768,超过 short 范围,编译器不会做转换//Type mismatch: cannot convert from int to short//short k = 2 * 16384;//常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换

short cThirty = 3 * 10;short three = 3;short ten = 10;//Type mismatch: cannot convert from int to short//short thirty = three * ten;

final short fTthree = 3;final short fTen = 10;//常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换

short fThirty = fTthree *fTen;final short a = 16384;final short b = 16383;//常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换

short c = a +b;

}

}

接下来根据代码罗列的两部分分别进行说明:

2.1、对于 +=, -=, *=, /=, Java编译器默认会添加强制类型转换,即 T a; X b; a += b; 等价于 T a; X b; a = (T) (a + b);

A compound assignment expression of the formE1 op= E2is equivalent toE1 = (T) ((E1) op (E2)), whereTis the type ofE1, except thatE1is evaluated only once.

For example, the following code is correct:

short x = 3;

x+= 4.6;

and results in x having the value 7 because it is equivalent to:

short x = 3;

x= (short)(x + 4.6);

笔者注:

实际上,直接加上强制类型转换的写法,也是大家都熟悉且理解起来最清晰的方式,可以避免可能潜在的类型不匹配时出现的精度损失问题,使用的时候需要注意。当然,笔者认为这些方式都没有好坏之分,正确地使用即可。

Java从语言规范层面对此做了限制。有兴趣的还可以通过 class文件和 javap -c 反汇编对所使用的字节码作进一步的研究。

知道了Java语言相关的规范约定,我们就可以看出,与之对应的是以下这种出现编译错误的写法(报错提示:Type mismatch: cannot convert from int to short):

short i = 1;//i + 1 是 int 类型,需要强制向下类型转换

i = i + 1;

2.2、常量表达式和编译器优化: 常量折叠

需要注意的是,前面的示例short x = 3;中的3其实默认是 int 类型,但是却可以赋值给short类型的x。这里涉及到到的其实是 常量表达式。

In addition, if the expression is a constant expression (

A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:

Byte and the value of the constant expression is representable in the type byte.

Short and the value of the constant expression is representable in the type short.

Character and the value of the constant expression is representable in the type char.

对于常量表达式,其结果是可以自动做窄化处理的,只要是在对应的数据类型范围内,Java编译器就进行做默认强制类型转换。

Some expressions have a value that can be determined at compile time. These are constant expressions (

true(short)(1*2*3*4*5*6)

Integer.MAX_VALUE/ 2

2.0 *Math.PI"The integer " + Long.MAX_VALUE + " is mighty big."

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (

通过常量表达式赋值的final变量都是常量,这种也是编译期可以确认最终值,会通过编译优化直接赋予最终值,而且可以直接依靠编译器做窄化处理。

对于这一块,其实对应的是一个比较基础的编译器优化:常量折叠(Constant Folding),有兴趣的可以自行搜索。stackoverflow 上由相关的讨论,参考[9]、[10]、[11]

笔者注:

尽管常量表达式最终都被编译器优化为直接值,但是为了清晰,提高可读性、可维护性,代码中没必要对常量直接换算,例如一天 24 * 60 * 60 秒,其实可以分别用可读性更强的final常量来表示。

Bloch大神的 Java Puzzlers 中也有相关的一些说明,有兴趣的可以去看看

⑦ byte a=1;byte b=2;byte c=a+b;byte d=1+2; 请问第三句和第四句的计算机底层计算分别是怎么样的

分析:

d = 1 + 2; 1和2是常量,为固定不变的数据,在编译的时候(编译器javac),已经确定了1+2的结果并没有超过byte类型的取值范围,可以赋值给变量d,因此d=1+2 是正确的。

常量优化机制

有一些计算,非常简单,例如常量和常量的计算就非常简单,在编译阶段就可以把这些简单的运算计算完。

反之, c = a + b ,a和b是变量,变量的值是可能变化的,在编译的时候,编译器javac不确定 a + b 的结果是什么,因此会将结果以int类型进行处理,所以int类型不能赋值给byte类型,因此编译失败。

⑧ 如何在编译java的时候,取消编译器对编译常量的优化

遇到的问题是想重新编译某个java文件(比如A.java),里面有个常量(比如finalinta)和上次编译时不一样,但是另一个使用A.class的a的文件(比如B.java)由于在javac在上次编译的时候将当时的A.class里面的常量直接给内联了,所以就达不到想要的效果。
如果是这样的话,对于String可以使用.intern()来防止编译器进行优化,对于其他类型,可以要么不定义为常量,要么将常量定义为private,然后使用一个static方法来返回这个常量。

⑨ 简述JAVA程序的编辑编译和运行过程

第一步(编译): 创建完源文件之后,程序会先被编译为.class文件。Java编译一个类时,如果这个类所依赖的类还没有被编译,编译器就会先编译这个被依赖的类,然后引用,否则直接引用,这个有点象make。

如果java编译器在指定目录下找不到该类所其依赖的类的.class文件或者.java源文件的话,编译器话报“cant find symbol”的错误。

第二步(运行):java类运行的过程大概可分为两个过程:1、类的加载 2、类的执行。需要说明的是:JVM主要在程序第一次主动使用类的时候,才会去加载该类。也就是说,JVM并不是在一开始就把一个程序就所有的类都加载到内存中,而是到不得不用的时候才把它加载进来,而且只加载一次。

特别说明:java类中所有public和protected的实例方法都采用动态绑定机制,所有私有方法、静态方法、构造器及初始化方法<clinit>都是采用静态绑定机制。而使用动态绑定机制的时候会用到方法表,静态绑定时并不会用到。

(9)java编译常量折叠扩展阅读:

Java整个编译以及运行的过程相当繁琐,本文通过一个简单的程序来简单的说明整个流程。

Java代码编译:是由Java源码编译器来完成;

Java字节码的执行:是由JVM执行引擎来完成

Java程序从源文件创建到程序运行要经过两大步骤:

1、源文件由编译器编译成字节码(ByteCode)

2、字节码由java虚拟机解释运行。因为java程序既要编译同时也要经过JVM的解释运行,所以说Java被称为半解释语言( "semi-interpreted" language)。

热点内容
随机启动脚本 发布:2025-07-05 16:10:30 浏览:517
微博数据库设计 发布:2025-07-05 15:30:55 浏览:20
linux485 发布:2025-07-05 14:38:28 浏览:299
php用的软件 发布:2025-07-05 14:06:22 浏览:751
没有权限访问计算机 发布:2025-07-05 13:29:11 浏览:428
javaweb开发教程视频教程 发布:2025-07-05 13:24:41 浏览:689
康师傅控流脚本破解 发布:2025-07-05 13:17:27 浏览:235
java的开发流程 发布:2025-07-05 12:45:11 浏览:681
怎么看内存卡配置 发布:2025-07-05 12:29:19 浏览:279
访问学者英文个人简历 发布:2025-07-05 12:29:17 浏览:828