Насколько дорого обходится понижение в Java 6?

Существует метод, который получает аргумент типа Collection, и ему необходимо использовать некоторые из методов класса List, когда он действительно работает с этим аргументом. Является ли ап-кастинг дорогим с точки зрения скорости?

List<Stuff> list = (List<Stuff>) collection;

Я также хотел бы отметить, что после этого объект collection никогда не используется, только list, и что он будет скомпилирован и запущен в Oracle Java 1.6.


person stackular    schedule 20.07.2013    source источник
comment
Ну, это не повышение. Это унизительно. И не стоит заморачиваться о расходах, когда других вариантов нет. Но, я думаю, это будет незначительно. Но лучше беспокоиться о некоторых ClassCastException во время выполнения.   -  person Rohit Jain    schedule 20.07.2013
comment
когда это работает с этим аргументом ‹-- что вы имеете в виду? Если это List, почему бы не вернуть List в первую очередь?   -  person fge    schedule 20.07.2013
comment
Учитывая, что дженерики в любом случае постоянно кастуются из-за того, как они были реализованы в Java, и маловероятно, что наносекунда или две когда-либо будут иметь какое-либо значение во всем, что вы пишете, я настоятельно рекомендую вам отказаться от этой конкретной головоломки преждевременной оптимизации.   -  person Brian Roach    schedule 20.07.2013
comment
@fge Я думаю, что идея в том, что если аргументом является List, то метод делает что-то необязательное помимо того, что он делает для всех Collections. Конечно, на расплывчатом выдуманном примере трудно сказать, в чем смысл.   -  person millimoose    schedule 20.07.2013
comment
Вполне реально застрять на интерфейсном методе, который в нашем конкретном приложении всегда получает список.   -  person Marko Topolnik    schedule 20.07.2013


Ответы (1)


Серьезные ответы дают фактические тесты. Например, я использовал этот код jmh-таргетинга:

public class Benchmark1
{
  static final List<Integer>[] lists = new List[10000]; static {
    for (int i = 0; i < lists.length; i++) {
      lists[i] = new ArrayList<Integer>(1);
      lists[i].add(1);
    }
  }
  static final Collection<Integer>[] colls = new Collection[lists.length]; static {
    for (int i = 0; i < colls.length; i++) colls[i] = lists[i];
  }


  @GenerateMicroBenchmark
  public long testNoDowncast() {
    long sum = (long)Math.random()*10;
    for (int i = 0; i < lists.length; i++) sum += lists[i].get(0);
    return sum;
  }
  @GenerateMicroBenchmark
  public long testDowncast() {
    long sum = (long)Math.random()*10;
    for (int i = 0; i < colls.length; i++) sum += ((List<Integer>)colls[i]).get(0);
    return sum;
  }
}

И jmh предоставил следующие результаты:

Benchmark          Mode Thr    Cnt  Sec         Mean   Mean error    Units
testDowncast      thrpt   1      5    5       18.545        0.019 ops/msec
testNoDowncast    thrpt   1      5    5       19.102        0.655 ops/msec

Если вам нужна интерпретация, то она следующая: нет никакой разницы.

person Marko Topolnik    schedule 20.07.2013
comment
+1 Я хочу иметь детей с этим постом. - person millimoose; 20.07.2013
comment
Дополнительный вопрос: как вы сравниваете jmh и суппорт, если вы знаете последний? - person fge; 20.07.2013
comment
@fge Я сначала работал с суппортом, а сейчас нахожусь на jmh, в основном по совету assylias. Они оба кажутся очень солидными, но поскольку этот, так сказать, изо рта лошади, то теперь я с ним. - person Marko Topolnik; 20.07.2013
comment
Хорошо, спасибо за информацию... На самом деле, я впервые слышу о jmh. Я посмотрю на это! - person fge; 20.07.2013
comment
«разница 4%» — более актуален доверительный интервал. Поскольку средние значения ± 1 SD (полученные из MSE) перекрываются, отсутствует статистически значимая разница. - person Konrad Rudolph; 20.07.2013
comment
@Marko Не принимайте мой комментарий всерьез, я на самом деле вне себя от радости, потому что это первый статистически точный микробенчмарк когда-либо, который я видел на Stack Overflow. Ты мой герой сегодня. :-) - person Konrad Rudolph; 20.07.2013
comment
Разве (long) Math.random() не просто 0? - person Peter Lawrey; 20.07.2013
comment
@PeterLawrey Ой... некоторых скобок не хватает, не так ли? Но это не очень важно, дело в том, чтобы помешать JITter, что, я думаю, в любом случае. Я исправлю это в будущем коде, спасибо, что заметили. - person Marko Topolnik; 21.07.2013
comment
@PeterLawrey Кстати, я думаю, что на самом деле ничего из этого не было необходимо, потому что приведение вниз никогда не может быть удалено JIT, поскольку это изменит поведение кода. - person Marko Topolnik; 21.07.2013
comment
@PeterLawrey Теперь я протестировал только for (int i = 0; i < lists.length; i++) { Integer x = lists[i].get(0); } и подобное для случая с понижением, и, как это ни парадоксально, результаты даже ближе, случай с понижением даже опережает с небольшим отрывом! Величина чисел практически такая же, как указано выше, поэтому элизии не произошло. - person Marko Topolnik; 21.07.2013
comment
@MarkoTopolnik Я ожидаю, что на одно восходящее преобразование уходит около 15 наносекунд, что похоже на результаты, которые вы видите. Ваш код намного дороже, чем само восхождение, что является хорошим ответом для ОП. ;) - person Peter Lawrey; 21.07.2013