靜態初始化中不能放入繁重計算,否則會變慢!
阿新 • • 發佈:2019-04-10
vat 可變 必須 long sta 直接 示例 填充 images
在類初始化期間計算不可變數據結果,並將結果保存在static final字段中是一種非常常見的做法。實際上,這正是靜態初始化器的設計目標。
以下是在初始化時構建一些靜態表的典型示例:
public class StaticExample { static final long[] TABLE = new long[100_000_000]; static { TABLE[0] = 0; for (int i = 1; i < TABLE.length; i++) { TABLE[i] = nextValue(TABLE[i - 1]); } } private static long nextValue(long seed) { return seed * 0x123456789L + 11; } ... }
在我的JDK 11.0.1筆記本電腦上,靜態初始化程序在大約540毫秒內填充100M元素的數組。
現在讓我們簡單地刪除static並填充構造函數中的數組。
public class NonStaticExample { final long[] TABLE = new long[100_000_000]; { TABLE[0] = 0; for (int i = 1; i < TABLE.length; i++) { TABLE[i] = nextValue(TABLE[i - 1]); } } private static long nextValue(long seed) { return seed * 0x123456789L + 11; } public static void main(String[] args) { new NonStaticExample(); } }
構造函數在138毫秒內填充類似的數組。幾乎快4倍!
為什麽靜態初始化器會變慢?這必須與JIT編譯有關。
解決方法非常簡單:
只是不要直接在未初始化的類中進行繁重的計算。如果將計算邏輯放在沒有靜態初始化程序的輔助類中,它將不會受到性能損失的影響。
public class StaticExample { static final long[] TABLE = Helper.prepareTable(); private static class Helper { static long[] prepareTable() { long[] table = new long[100_000_000]; for (int i = 1; i < table.length; i++) { table[i] = nextValue(table[i - 1]); } return table; } static long nextValue(long seed) { return seed * 0x123456789L + 11; } } }
靜態初始化中不能放入繁重計算,否則會變慢!