Это динамическая отправка?
Это динамическая отправка:
abstract class A{
public method Meth1(){
//somecode
}
}
class B extends A{
}
class C extends A{
}
В другом классе полностью:
Some_Method(A a){
a.Meth1();
}
Я не уверен, что это динамическая отправка, потому что поведение одинаково на обоих подклассах?
Если это не так, будет ли это динамическая отправка, если поведение определено для подклассов?
4 ответа
Я не уверен, что вы говорите о своем конкретном вопросе (может быть некоторая оптимизация, специфичная для реализации, которая обойдёт проверку типов во время выполнения, если статически известно, что вызванный метод объявлен только в одном классе), но, действительно, динамическая диспетчеризация позволяет фактическая реализация Meth1
метод должен быть определен во время выполнения. Так что, даже если прямо сейчас, ни B
ни C
переопределение Meth1
позже, при переопределении, динамическая диспетчеризация будет гарантировать, что если тип времени выполнения формального параметра a
является B
тогда фактическая реализация будет B
, Аналогично в случае C
,
Сравните это с перегрузкой метода в Java, где фактический метод определяется во время компиляции на основе объявленного типа используемых аргументов.
public class Overloading {
public static class User {}
public static class Admin extends User {}
public static String foo(User user) {
return "User specific method";
}
public static String foo(Admin admin) {
return "Admin specific method";
}
// This will print "User specific method" two times, because both
// user1 and user2 have same compile time type, i.e., User. Runtime
// type does not matter.
public static void main(String[] args) {
User user1 = new User();
System.out.println(foo(user1));
User user2 = new Admin();
System.out.println(foo(user2));
}
}
Это динамическая диспетчеризация, потому что при создании байт-кода для вызывающего класса компилятор не может предположить, что он знает всю вселенную классов.
Также не будет интерпретатор байт-кода или JIT-компилятор во время выполнения, по крайней мере, потому что классы могут быть загружены динамически.
На мой взгляд, это не оставляет java никакой другой опции, кроме как использовать динамическую диспетчеризацию, а не "вырезать углы", то есть оптимизировать вызовы в вызовы базового класса.
Да, это!.
Потому что в Java все методы экземпляра являются виртуальными по умолчанию. ( Можете ли вы написать виртуальные функции / методы в Java?)
Затем разрешите a.Meth1() во время выполнения. Помните, что вы можете динамически загружать новый JAR с классом, производным от A, имеющим переопределение этого метода.
Динамическая отправка - это когда реализация метода выбирается на основе фактического, а не объявленного типа. Java не поддерживает динамическую диспетчеризацию, кроме как через отражение. Это статически типизированная полиморфная отправка.
Если у вас загружена одна реализация, JVM будет применять моморфную оптимизацию (получая очень быстрые вызовы), которая будет отменена, когда JVM увидит, что вторая реализация передана тому же коду.
Возможно, вы слышали о новом байт-коде "invokedynamic", который реализует динамическую диспетчеризацию в JVM, но он предназначен для использования другими языками JVM, и программы Java не будут использовать его, за исключением случаев генерации байт-кода.
[Править] Вот простой пример:
Collection<Integer> c = new ArrayList<Integer>(Arrays.asList(2, 1, 0));
c.remove(2); // Collection.remove(E element) or List.remove(int idx)?
assert c.equals(Arrays.asList(1, 0)); // passes in case of static dispatch
assert c.equals(Arrays.asList(2, 1)); // fails - would pass in case of dynamic dispatch