Кто-то спросил это снова (дубликат), что заставило меня немного углубиться в этом вопросе.
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
ArrayList<String> aList = new ArrayList<String>();
aList.add("a");
aList.add("b");
}
Если мы используем средство просмотра байт-кода (я использовал http://asm.ow2.org/eclipse/index.html), мы увидим следующее (только инициализация и назначение списка) для нашего списка сниппета:
L0
LINENUMBER 9 L0
NEW ArrayList
DUP
INVOKESPECIAL ArrayList.<init> () : void
ASTORE 1
L1
LINENUMBER 10 L1
ALOAD 1: list
LDC "a"
INVOKEINTERFACE List.add (Object) : boolean
POP
L2
LINENUMBER 11 L2
ALOAD 1: list
LDC "b"
INVOKEINTERFACE List.add (Object) : boolean
POP
и для alist :
L3
LINENUMBER 13 L3
NEW java/util/ArrayList
DUP
INVOKESPECIAL java/util/ArrayList.<init> ()V
ASTORE 2
L4
LINENUMBER 14 L4
ALOAD 2
LDC "a"
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
L5
LINENUMBER 15 L5
ALOAD 2
LDC "b"
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
Разница в список в итоге вызывает INVOKEINTERFACE , тогда как aList вызывает INVOKEVIRTUAL . В соответствии со ссылкой на плагин Bycode Outline,
invokeinterface используется для вызова метода, объявленного в Java
интерфейс
в то время как invokevirtual
вызывает все методы, кроме методов интерфейса (которые используют
invokeinterface), статические методы (которые используют invokestatic) и несколько
особые случаи обрабатываются invokespecial.
В итоге invokevirtual выскакивает objectref из стека, в то время как для invokeinterface
интерпретатор выталкивает 'n' элементов из стека операндов, где 'n' - 8-битный без знака
целочисленный параметр, взятый из байт-кода. Первый из этих предметов
objectref, ссылка на объект, метод которого вызывается.
Если я правильно понимаю, разница в том, как каждый способ извлекает objectref .