Всегда ли переопределение метода во время выполнения полиморфизма?

Всегда ли полиморфизм во время выполнения происходит с переопределением метода или только если метод вызывается после назначения объекта подкласса переменной суперкласса во время переопределения метода?

Например:

class A
{
    public void myFunc()
    {
     System.out.println("Something");
     }
}

class B extends A
{
    public void myFunc()
    {
    System.out.println("Something else");
     }

     public static void main (String args[])
     {
     A obj = new B();
     obj.myFunc(); //Is only this call resolved at run time?

     A obj2 = new A();
     obj2.myFunc(); //Or is this call too resolved at run time?

     B obj3 = new B();
     obj3.myFunc(); //Is this call resolved at compile time?
     }
}

Пожалуйста помоги!

0 ответов

При переопределении метода JVM всегда заботится о разрешении метода на основе ОБЪЕКТА ВРЕМЕНИ РАБОТЫ. Да, все эти вызовы будут разрешены во время выполнения.

A obj = new B();
obj.myFunc();
  • здесь ссылочная переменная относится к классу A, но объект относится к классу B. Следовательно, будет вызван метод myFunc класса B

A obj2 = new A();

obj2.myFunc();

  • здесь ссылочная переменная относится к классу A, а объект также к классу A. Следовательно, будет вызван метод myFunc класса A

B obj3 = new B();

obj3.myFunc();

  • здесь ссылочная переменная относится к классу B, а объект также к классу B. Следовательно, будет вызван метод myFunc класса B.

Являются ли компилятор на самом деле в состоянии оптимизировать любого или все три вызова методов и разрешить вызовы во время компиляции в настоящее время или в какой - то реализации в будущей не имеет никакого значения: все три вызовов метода являются примерами выполнения полиморфизма, также известные как динамическая диспетчеризация Это контрастировало с так называемым статическим полиморфизмом, также известным как перегрузка методов, который представляет собой класс, имеющий несколько методов с одним и тем же именем, но с разными типами аргументов.

Вот небольшая программа на Java:

public class Test {


    public void foo(String inputString)
    {
        System.out.println(inputString);
    }


    public static void main(String[] args) {
        Test test = new Test();
        test.foo("a"); # very obvious method invocation
    }

}

Человеку совершенно ясно, какой метод будет вызван во время выполнения. Вот дизассемблированный байт-код:

Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void foo(java.lang.String);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_1
       4: invokevirtual #3                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       7: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #4                  // class Test
       3: dup
       4: invokespecial #5                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #6                  // String a
      11: invokevirtual #7                  // Method foo:(Ljava/lang/String;)V
      14: return
}

Инструкция 11 - это диспетчеризация виртуального метода во время выполнения.

Но, как я уже сказал, даже если в какой-то будущей реализации компилятора это будет оптимизировано для другого вызова, это будет просто деталью реализации.

  • Частные, конечные и статические члены (методы и переменные) используют статическую привязку.

  • В то время как для виртуальных методов (в Java методы являются виртуальными по умолчанию) привязка выполняется во время выполнения на основе объекта, удерживаемого переменной.

Итак, чтобы ответить на ваш вопрос, разрешение метода всегда выполняется во время выполнения для всех следующих случаев. (Независимо от того, назначен ли объект подкласса переменной суперкласса или тот же тип объекта, удерживаемого переменной)

    A obj = new B();
    obj.myFunc();
 
    A obj2 = new A();
    obj2.myFunc();

    B obj3 = new B();
    obj3.myFunc();

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

Вы сомневаетесь в этом примере: A a = new A();но это эквивалентно этому A a = MyFactory.get();

Возможно, JVM выполняет некоторую оптимизацию final A a = new B(); чтобы избежать поиска правильной реализации?

Как правило, концепция полиморфизма связана с использованием разных форм одного типа (класс / интерфейс), поэтому подклассы должны иметь аналогичный контракт в соответствии с типом супер.

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

Другие вопросы по тегам