標籤:變數 常量 class 最佳化 www 初始 val ssi ret
在反射那些事反射這篇文章有談到一個常量運算式的問題,想單獨拿出來研究一下。
private final int INT_VALUE=12;//常量運算式if(a>INT_VALUE){ //todo}
那麼java編譯器會對常量運算式進行一個最佳化,變成如下:
if(a>12){ //todo}
在知乎上看到這個觀點: 把常量運算式的值求出來作為常量嵌在最終產生的程式碼中,這種最佳化叫做常量摺疊(constant folding)。
原來這叫做常量摺疊。
簡單舉個例子,上面例子沒有太直觀。
public class ConstantTest { private final int a=12; //常量運算式 private int b=12; //普通成員變數 private final boolean flag=null==null?true:null; //非常量運算式 public void solve(int b){ if(b>a){ System.out.println("yep"); } } public void solve(){ if(flag){ System.out.println(b); } } public static void main(String[] args) { ConstantTest test=new ConstantTest(); test.solve(13); test.solve(); }}
我們對ConstantTest.class檔案進行反編譯看看:
package com.reflect;import java.io.PrintStream;public class ConstantTest { private final int a = 12; private int b = 12; private final boolean flag = null == null ? Boolean.valueOf(true) : null; public void solve(int b) { if (b > 12) { //這裡我們看到了編譯器直接進行了最佳化,把a直接用12來進行替代。 System.out.println("yep"); } } public void solve() { if (this.flag) { //非常量運算式和普通成員變數沒有發生變化 System.out.println(this.b); } } public static void main(String[] args) { ConstantTest test = new ConstantTest(); test.solve(13); test.solve(); }
舉一些例子符合常量運算式和不符合常量運算式的例子:
public class ConstantTest { private final int x=2; //yes private final int y=x+2;//yes private final int f;//no 沒有被初始化 private final int z= Integer.valueOf("42");//no 不是常量運算式 public ConstantTest() { this.f=2; } public static int t(){ final int x=2; int y=new int[2].length; return x+y; } public static int s(){ return 12*18-12+30; } public void test(){ System.out.println(x+" "+y+" "+f+" "+z); }}
反編譯結果:
package com.reflect;import java.io.PrintStream;public class ConstantTest { private final int x = 2; private final int y = 4; private final int f = 2; private final int z = Integer.valueOf("42"); public static int t() { int x = 2; int y = new int[2].length; return 2 + y; } //向這裡有人說是可以直接被最佳化成 public static int t() { return 4; //可是我的ide並沒有 估計其他是可以的 } public static int s() { return 234; //上面複雜的常量運算被最佳化成最終的計算結果 } public void test() { System.out.println("2 4 " + this.f + " " + this.z); }}
參考: 對於一個很複雜的常量運算式,編譯器會算出結果再編譯嗎?
參考: Chapter 15. Expressions
關於常量運算式