Является ли Boolean.TRUE, а не true оптимизацией автобокса?

Я видел следующий код и задавался вопросом о намерениях кодера. Связано ли это с производительностью автобокса?

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

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

map.put("doesntMatter", true);

Есть ли польза от первого?


person SurenNihalani    schedule 21.06.2013    source источник
comment
Я бы сказал, что компилятор достаточно умен, поэтому любой из них будет иметь тот же эффект. - Мы могли бы сделать тест, хотя.   -  person acdcjunior    schedule 21.06.2013
comment
Либо то, что сказал @acdcjunior, либо во время выполнения, JIT выяснит это. Так что никакого реального интереса в конечном счете.   -  person fge    schedule 21.06.2013
comment
Только что проверил с помощью Oracle javap, и, хорошо это или плохо, map.put("doesntMatter", true) преобразуется в map.put("doesntMatter", Boolean.valueOf(1)). Поэтому он генерирует одну дополнительную инструкцию (которая помещает 1 в стек перед вызовом метода valueOf) и использует invokestatic вместо getstatic (используется в первом операторе). Мне трудно делать какие-либо выводы из этого (потому что JIT вступит в игру, когда придет время; и разные компиляторы генерируют разные байт-коды), но то, что я только что описал, — это то, что на самом деле происходит с Oracle javac и javap.   -  person acdcjunior    schedule 21.06.2013
comment
На самом деле это не дублирующий вопрос, поскольку этот вопрос касается конкретно контекста, в котором требуется Boolean, а не boolean.   -  person Raedwald    schedule 21.06.2013


Ответы (3)


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

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-компилятор выполнит свою работу и оптимизирует его.

person jlordo    schedule 21.06.2013
comment
Я не совсем уверен, что мы должны здесь увидеть... Не могли бы вы уточнить. Также возможно также сравнить его с Map<String boolean>? - person David says Reinstate Monica; 21.06.2013
comment
@ Dgrin91: Map<String, boolean> не компилируется. Я написал краткое заключение. - person jlordo; 21.06.2013
comment
@Dgrin91: Это именно то, о чем я говорил invokestatic #26 <java/lang/Boolean/valueOf(Z)Ljava/lang/Boolean;>. - person Bhesh Gurung; 21.06.2013

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

Результаты :

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));
  }
}
person Jonathan Drapeau    schedule 21.06.2013

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

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

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

private final boolean value;

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

person David says Reinstate Monica    schedule 21.06.2013
comment
Уверены ли вы? Значение TRUE установлено как static. - person Raedwald; 21.06.2013
comment
Boolean.TRUE не вызывает конструктор. Конструктор вызывается только один раз при загрузке класса. Boolean.TRUE просто разыменовывает созданный объект. - person jlordo; 21.06.2013
comment
@jlordo Ой, вы правы. Я неправильно это понял. - person David says Reinstate Monica; 21.06.2013