2015-10-11 4 views
1

This Википедии гласит:Политизм подтипов: всегда поздняя привязка?

Поскольку конкретный тип полиморфного объекта не известен до выполнения (в целом), то выполняется функция динамически связаны. Возьмем, к примеру, следующий Java-код:

public void foo(java.util.List<String> list) { 
    list.add("bar"); 
} 

Список представляет собой интерфейс, так что список должен относиться к подтипу ней. Является ли ссылка ссылкой на LinkedList, ArrayList или какой-либо другой подтип ? Фактический метод, на который ссылается add, неизвестен до выполнения.

Рассмотрим следующий пример:

List<String> list; 

list = new LinkedList<String>(); 
foo(list); 

list = new ArrayList<String>(); 
foo(list); 

Почему не фактический метод ссылки здесь не знаю, до выполнения? Не удалось ли компилятору проверить каждый вызов foo, из которого вводится объект list? Конечно, это возможно только в том случае, если программа детерминирована и не задействована случайность (например, взаимодействие с пользователем).

Это что-то (в общем) в цитируемом заявлении о том или о чем я не понимаю?

В специальном случае, когда программа детерминирована, используется статическое связывание или есть - в Java - всегда используется динамическое связывание, независимо от того, что возможно? Если да, то почему?

+1

Это * может *, но это было бы очень много работы, чтобы получить не большую выгоду. –

+0

@OliverCharlesworth, выигрыш большой и превосходит массу работы, и на самом деле это делает это! –

ответ

2

В заявлении говорится о общем кейс. Учитывая только код примера Википедии, невозможно указать конкретный тип параметра list. В вашем примере можно рассказать конкретные типы.

Время выполнения Java разрешено и фактически вызывает вызовы метода devirtualize, если он может определить конкретный тип переменной.

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

1

Девиртуализация не формируется во время компиляции источника java в java-байт-код. В противном случае это было бы довольно хрупким. Обратите внимание, что скомпилированные классы Java обычно сохраняют двоичную совместимость (с некоторыми известными исключениями). Таким образом, если ваш foo находится в отдельном классе и вы перекомпилируете только этот класс, то вызов класса foo должен работать с новым кодом без перекомпиляции.

Однако девиртуализация возможна во время выполнения и фактически выполняется большинством современных JVM (включая JVM Oracle HotSpot или курс). Этот метод, вероятно, будет полностью включен в JIT-компиляцию: вызовы foo, LinkedList.add и ArrayList.add будут объединены в тело метода вызывающего абонента.

В целом цитата из Википедии верна: фактический метод, на который ссылается add, неизвестен до выполнения. Однако это не означает, что вызов остается полиморфным, поскольку время выполнения JVM - довольно сложная вещь, которая включает в себя интерпретатор, JIT-компиляцию и выполнение JIT-скомпилированного кода.

 Смежные вопросы

  • Нет связанных вопросов^_^