Статьи

Autoboxing

Автобокс понятен всем Java-разработчикам, начиная с Java 1.5. Ну, я могу быть слишком оптимистичным. По крайней мере, все разработчики должны быть в порядке с автобоксом. Ведь на странице ORACLE есть хороший учебник по этому поводу.

Автобокс — это явление, когда компилятор Java автоматически генерирует код, создавая объект из примитивного типа, когда это необходимо. Например, вы можете написать:

1
Integer a = 42;

и он автоматически сгенерирует код JVM, который помещает значение int 42 в объект Integer . Это так мило со стороны компилятора, что он делает это для нас, что через некоторое время мы, программисты, просто забываем о сложности, стоящей за ним, и время от времени мы сталкиваемся со стеной.

Например, у нас есть double.class и Double.class . Оба они являются объектами (как класс, и каждый класс сам по себе является объектом в permgen или просто в куче в пост-пермгенской версии JVM). Оба эти объекта имеют тип Class . Более того: начиная с Java 1.5 оба они имеют тип Class<Double> .

Если два объекта имеют одинаковый тип, они также должны быть совместимы по присваиванию, не так ли. Кажется, очевидное утверждение. Если у вас есть объект O a и объект O b тогда вы можете назначить a = b .

Глядя на код, мы можем понять, что забываем, а не видим:

1
2
3
4
5
6
7
8
9
public class TypeFun {
    public static void main(String[] args) {
        // public static final Class<Double>   TYPE = (Class<Double>)Class.getPrimitiveClass("double");
        System.out.println("Double.TYPE == double.class: " + (Double.TYPE == double.class));
        System.out.println("Double.TYPE == Double.class: " + (Double.TYPE == Double.class));
        System.out.println("double.class.isAssignableFrom(Double.class): " + (double.class.isAssignableFrom(Double.class)));
        System.out.println("Double.class.isAssignableFrom(double.class): " + (Double.class.isAssignableFrom(double.class)));
    }
}

в результате чего:

1
2
3
4
Double.TYPE == double.class: true
Double.TYPE == Double.class: false
double.class.isAssignableFrom(Double.class): false
Double.class.isAssignableFrom(double.class): false

Это означает, что примитивная пара Double является double.class (не удивительно). Даже если одно не может быть назначено от другого. Мы можем взглянуть на источник хотя бы одного из них. Источник класса Double находится в RT.jar и является открытым исходным кодом. Там вы можете увидеть, что:

1
public static final Class<Double> TYPE = (Class<Double>) Class.getPrimitiveClass("double");

Почему он использует этот странный Class.getPrimitiveClass("double") вместо double.class ? Это пара примитивов типа Double .

Ответ не тривиален, и вы можете углубиться в детали Java и JVM. Поскольку double — это не класс, в действительности нет ничего лучше double.class . Вы по-прежнему можете использовать этот литерал в исходном коде Java, и именно здесь язык Java, компилятор и среда выполнения имеют сильную зависимость. Компилятор знает, что класс Double определяет поле с именем TYPE обозначающее его примитивный тип. Всякий раз, когда компилятор видит double.class в исходном коде, он генерирует код JVM Double.TYPE (попробуйте и затем используйте javap для декодирования сгенерированного кода!). Именно по этой причине разработчик РТ не мог написать:

1
public static final Class<Double> TYPE = double.class;

в источник класса Double . Это скомпилируется в эквивалент кода:

1
public static final Class<Double> TYPE = TYPE;

Как происходит автобокс? Источник:

1
Double b = (double)1.0;

полученные результаты:

1
2
3
0: dconst_1     
         1: invokestatic  #2                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
         4: astore_1

однако, если мы заменим две буквы «d»:

1
double b = (Double)1.0;

тогда мы получим:

1
2
3
4
0: dconst_1     
         1: invokestatic  #2                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
         4: invokevirtual #3                  // Method java/lang/Double.doubleValue:()D
         7: dstore_1

Который объясняет многое. Экземпляры класса double.class и класса Double.class не совместимы по назначению. Автобокс решает это. Java 4 была давным-давно, и мы, к счастью, забыли об этом.

Ваша домашняя работа: перечитайте то, что происходит с автобоксом, когда у вас перегружены методы с аргументами типа «класс» и соответствующего типа примитива.

Ссылка: Автобокс от нашего партнера JCG Питера Верхаса в блоге Java Deep .