Затраты на выполнение приведения бетонной коллекции к ее интерфейсу - PullRequest
0 голосов
/ 05 сентября 2011

Когда я пишу какой-то API, он иногда будет использовать Collection<Model> в качестве параметра. Конечно, вы можете использовать ArrayList, если знаете, что ArrayList уже достаточно для обработки всего варианта использования.

У меня вопрос, есть ли значительные потери производительности, когда, например, при передаче параметра передается ArrayList<Model> в Collection<Model>.

Повлияет ли размер коллекции на эффективность литья? Любой совет?

Спасибо за ответ Питера.

Я думаю, что ответ достаточно хорош, чтобы помешать мне тратить время на его изменение.

EDIT

Как сказано в принятом ответе, стоимость фактически оплачивается при вызове методов интерфейса. Нельзя свободно сохранять такую ​​гибкость. Но стоимость не так значительна.

Ответы [ 3 ]

6 голосов
/ 05 сентября 2011

Как и большинство вопросов производительности, ответ; напишите ясный и простой код, и приложение, как правило, тоже работает хорошо.

Приведение к интерфейсу может занять около 10 нс (меньше, чем вызов метода). В зависимости от того, как оптимизирован код, оно может быть слишком маленьким для измерения.

Приведение между универсальными типами - это проверка времени компилятора, на самом деле во время выполнения ничего не происходит.

Когда вы разыгрываете, меняется тип ссылки, все ссылки имеют одинаковый размер. Размер того, на что они указывают, не имеет значения.

Кстати: все объекты ArrayList имеют одинаковый размер, все объекты LinkedList имеют одинаковый размер, все объекты HashMap имеют одинаковый размер и т. Д. Они могут ссылаться на массив разных размеров в разных коллекциях.


Вы можете увидеть разницу в коде, который не был JITed.

public static void main(String... args) throws Throwable {
  ArrayList<Integer> ints = new ArrayList<>();
  for(int i=0;i<100;i++) ints.add(i);
  sumSize(ints, 5000);
  castSumSize(ints, 5000);
  sumSize(ints, 5000);
  castSumSize(ints, 5000);
}

public static long sumSize(ArrayList<Integer> ints, int runs) {
  long sum = 0;
  long start = System.nanoTime();
  for(int i=0;i<runs;i++)
    sum += ints.size();
  long time = System.nanoTime() - start;
  System.out.printf("sumSize: Took an average of %,d ns%n", time/runs);
  return sum;
}

public static long castSumSize(ArrayList<Integer> ints, int runs) {
  long sum = 0;
  long start = System.nanoTime();
  for(int i=0;i<runs;i++)
    sum += ((Collection) ints).size();
  long time = System.nanoTime() - start;
  System.out.printf("castSumSize: Took an average of %,d ns%n", time/runs);
  return sum;
}

печать

sumSize: Took an average of 31 ns
castSumSize: Took an average of 37 ns
sumSize: Took an average of 28 ns
castSumSize: Took an average of 34 ns

однако, различие, вероятно, связано с тем, что вызовы методов более дороги. Единственная разница в байт-коде:

invokevirtual   #9; //Method java/util/ArrayList.size:()I

и

invokeinterface #15,  1; //InterfaceMethod java/util/Collection.size:()I

Как только JIT оптимизирует код, различий не будет. Запустившись достаточно долго, время для -сервера JVM падает до 0 нс, поскольку он обнаруживает, что цикл ничего не делает. ;)

0 голосов
/ 05 сентября 2011

Коллекция представляет собой интерфейс . Вы всегда должны предоставить конкретную реализацию , такую ​​как ArrayList.

Обычно это будет

Collection<Model> myCollection = new ArrayList<Model>();

Проектирование интерфейсов на самом деле является хорошей практикой, поэтому используйте Collection в качестве параметра вашего метода.

0 голосов
/ 05 сентября 2011

По сравнению с чем угодно с любым объектом: абсолютно нет.

И даже если это произойдет, убедитесь, что любая программа включает в себя вещи, которые занимают миллионы больше времени!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...