2013-06-21 1 views
1

Я увидел следующий код и задавался вопросом о намерении кодера. Это связано с эксплуатацией автобоксинга?Действительно ли Boolean.TRUE, а не истинная оптимизация автобоксинга?

map.put("doesntMatter", Boolean.TRUE); 

Он мог бы сделать:

map.put("doesntMatter", true); 

Любые выгоды от этого в первую очередь?

+0

Я бы сказал, что компилятор достаточно умен, так любой из них будет иметь тот же эффект. - Мы могли бы пройти тест. – acdcjunior

+0

Либо что сказал @acdcjunior, либо во время выполнения JIT это выяснит. Итак, никакого реального интереса в конечном счете. – fge

+1

Только что проверено через 'javap' из Oracles, и, good or no good,' map.put ("doesntMatter", true) 'преобразуется в' map.put ("doesntMatter", Boolean.valueOf (1)) '. Таким образом, он генерирует одну дополнительную инструкцию (которая толкает «1» в стек перед вызовом метода «valueOf») и использует 'invokestatic' вместо' getstatic' (используется в первом заявлении). Мне сложно сделать какие-либо выводы из этого (потому что JIT войдет в игру, когда придет реальное время, а разные компиляторы генерируют разные байт-коды), но то, что я только что описал, - это то, что на самом деле происходит с «javac» и «javap» Oracle '. – acdcjunior

ответ

0

Из исходного кода -

public static final Boolean TRUE = new Boolean(true); 

public Boolean(boolean value) { 
    this.value = value; 
} 

private final boolean value; 

Так как вы можете видеть, TRUE вызывает конструктор, который просто устанавливает значение. Поэтому теоретически это немного менее эффективно, потому что он делает небольшую дополнительную работу, чтобы получить тот же результат.

+1

Вы уверены? Значение TRUE устанавливается как 'static'. – Raedwald

+1

'Boolean.TRUE' не вызывает конструктор. Конструктор вызывается только один раз, когда класс загружается. 'Boolean.TRUE' просто разыгрывает созданный объект. – jlordo

+0

@jlordo Упс, вы в порядке. Я неправильно понял это. –

4

Я написал пример:

public class Demo { 

    Map<String, Boolean> map = new HashMap<>(); 

    void primitive() { 
     map.put("a", true); 
    } 

    void object() { 
     map.put("b", Boolean.TRUE); 
    } 
} 

посмотреть на байткод из primitive()

0 aload_0 
1 getfield #17 <Demo/map Ljava/util/Map;> 
4 ldC#24 <a> 
6 iconst_1 
7 invokestatiC#26 <java/lang/Boolean/valueOf(Z)Ljava/lang/Boolean;> 
10 invokeinterface #32 <java/util/Map/put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;> count 3 
15 pop 
16 return 

и байткод из object()

0 aload_0 
1 getfield #17 <Demo/map Ljava/util/Map;> 
4 ldC#39 <b> 
6 getstatiC#41 <java/lang/Boolean/TRUE Ljava/lang/Boolean;> 
9 invokeinterface #32 <java/util/Map/put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;> count 3 
14 pop 
15 return 

Вывод:

при использовании примитива есть дополнительный шаг, вызывающий Boolean.valueOf(), но если вы часто запускаете этот фрагмент кода, компилятор JIT выполнит свою работу и оптимизирует ее.

+0

Я не совсем уверен, что мы можем увидеть здесь ... Не могли бы вы рассказать подробнее. Также возможно также сравнить его с 'Map '? –

+2

@ Dgrin91: 'Map ' не будет компилироваться. Я написал короткий вывод. – jlordo

+0

@ Dgrin91: Это именно то, что я говорил 'invokestatiC# 26 '. –

1

Преимущества не во время выполнения, так как этот маленький тест кода показывает:

Результаты:

Time with primitives : 3334779619 
Time with Object : 4092034749 
Time with primitives : 3670851766 
Time with Object : 2748035018 
Time with Object : 3738916372 
Time with primitives : 2975196722 
Time with Object : 2514328271 
Time with primitives : 2588980283 
Time with Object : 2696162369 
Time with primitives : 2615258656 
Time with primitives : 2633824223 
Time with Object : 2489779261 

Код:

import java.util.HashMap; 
import java.util.Map; 

import javax.swing.JOptionPane; 

public class Test 
{ 
    public static void main(String[] args) { 
    JOptionPane.showMessageDialog(null, "Start"); 

    createWithPrimitive(); 
    createWithObject(); 
    createWithPrimitive(); 
    createWithObject(); 
    createWithObject(); 
    createWithPrimitive(); 
    createWithObject(); 
    createWithPrimitive(); 
    createWithObject(); 
    createWithPrimitive(); 
    createWithPrimitive(); 
    createWithObject(); 

    System.exit(0); 
    } 

    private static void createWithObject() { 
    long time = System.nanoTime(); 
    Map<Integer, Boolean> testMap = new HashMap<Integer, Boolean>(); 
    for (int i = 1; i <= 10000000; i++) { 
     if (i % 2 == 0) { 
     testMap.put(i, Boolean.TRUE); 
     } else { 
     testMap.put(i, Boolean.FALSE); 
     } 
    } 

    System.out.println("Time with Object : " + (System.nanoTime() - time)); 
    } 

    private static void createWithPrimitive() { 
    long time = System.nanoTime(); 
    Map<Integer, Boolean> testMap = new HashMap<Integer, Boolean>(); 
    for (int i = 1; i <= 10000000; i++) { 
     if (i % 2 == 0) { 
     testMap.put(i, true); 
     } else { 
     testMap.put(i, false); 
     } 
    } 

    System.out.println("Time with primitives : " + (System.nanoTime() - time)); 
    } 
}