Java 的基本数据类型(int、double、 char)都不是对象。但由于很多Java代码需要处理的是对象(Object),Java给所有基本类型提供了包装类(Integer、Double、Character)。有了自动装箱,你可以写如下的代码
Character boxed = 'a';
char unboxed = boxed;
编译器自动将它转换为
Character boxed = Character.valueOf('a');
char unboxed = boxed.charValue();
然而,Java虚拟机不是每次都能理解这类过程,因此要想得到好的系统性能,避免不必要的装箱很关键。这也是 OptionalInt 和 IntStream 等特殊类型存在的原因。在这篇文章中,我将概述JVM很难消除自动装箱的一个原因。
实例
例如,我们想要计算任意一类数据的编辑距离(Levenshtein距离),只要这些数据可以被看作一个序列:
public class Levenshtein{ private final Function> asList; public Levenshtein(Function> asList) { this.asList = asList; } public int distance(T a, T b) { // Wagner-Fischer algorithm, with two active rows List aList = asList.apply(a); List bList = asList.apply(b); int bSize = bList.size(); int[] row0 = new int[bSize + 1]; int[] row1 = new int[bSize + 1]; for (int i = 0; i row0[i] = i; } for (int i = 0; i < bSize; ++i) { U ua = aList.get(i); row1[0] = row0[0] + 1; for (int j = 0; j < bSize; ++j) { U ub = bList.get(j); int subCost = row0[j] + (ua.equals(ub) ? 0 : 1); int delCost = row0[j + 1] + 1; int insCost = row1[j] + 1; row1[j + 1] = Math.min(subCost, Math.min(delCost, insCost)); } int[] temp = row0; row0 = row1; row1 = temp; } return row0[bSize]; } } |
只要两个对象可以被看作List,这个类就可以计算它们的编辑距离。如果想计算String类型的距离,那么就需要把String转变为List类型:
public class StringAsList extends AbstractList{
private final String str;
public StringAsList(String str) {
this.str = str;
}
@Override
public Character get(int index) {
return str.charAt(index); // Autoboxing! }
@Override
public int size() {
return str.length();
}
}
...
Levenshteinlev = new Levenshtein<>(StringAsList::new);
lev.distance("autoboxing is fast", "autoboxing is slow"); // 4
由于Java泛型的实现方式,不能有List类型,所以要提供List和装箱操作。(注:Java10中,这个限制也许会被取消。)