левый и правый объекты оцениваются / разрешаются во время выполнения или во время компиляции? - PullRequest
4 голосов
/ 01 июня 2019

Обращаясь к упражнению с книгой ...

Имея следующий код ..

Left left = createLeftInstance ();
Right right = createRightInstance ();

... и учитывая, что оба вышеупомянутых метода могут возвращать экземпляр всехподклассы Left и Right, в Java вызов следующего метода ...

left.invoke (right);

как разрешается:

  • A) в зависимости от типа времени выполнения leftи время компиляции справа
  • B) на основе типа времени компиляции слева и времени выполнения справа
  • C) на основе типа времени компиляции слева и времени компиляции справа
  • D) на основе типа времени выполнения слева и времени выполнения справа

Ответы [ 3 ]

2 голосов
/ 01 июня 2019

На самом деле, я думаю, что технически правильный ответ - «ничего из вышеперечисленного».

  • Во время компиляции вам необходимо знать объявленные типы переменной left (Left) и переменная right (Right).Это определит, какая перегрузка метода 1 метода Left::invoke наиболее применима к параметру типа Right.

  • Во время выполнения фактический типleft определит, какой фактический метод вызывается.

Таким образом, полный ответ:

E) на основе типов времени компиляции И исполнения left и для типа времени компиляции right.

Однако я подозреваю, что смысл этого вопроса в учебнике - помочь вам отличить разрешение во время компиляции не перегруженногометоды и методы диспетчеризации.Для этого A) является «достаточно корректным».


1 - Для определения компилятору необходимо сравнить Right и его супертипы с различными перегрузками метода invoke метод, объявленный Left и его супертипы.Если имеется несколько перегрузок, компилятор должен выбрать «наиболее конкретную применимую» перегрузку.

1 голос
/ 01 июня 2019

A) является правильным ответом здесь.

Следующий код демонстрирует, что.

    public class Main001 {

        public static void main(String[] args) {
            A right = createRightInstance();
            B left = createLeftInstance();

            left.invoke(right);
            System.out.println("Done!!!");
        }

        public static B createLeftInstance() {
            return new B2();
        }

        public static A createRightInstance() {
            return new A2();
        }

    }

    class A{

    }

    class A1 extends A{

    }

    class A2 extends A1{

    }

    class B{
        public void invoke(A x) {
            System.out.println("Invoking method A on B with argument " + x.getClass().getName());
        }
        public void invoke(A1 x) {
            System.out.println("Invoking method A1 on B with argument " + x.getClass().getName());
        }
        public void invoke(A2 x) {
            System.out.println("Invoking method A2 on B with argument " + x.getClass().getName());
        }
    }

    class B1 extends B{
        public void invoke(A x) {
            System.out.println("Invoking method A on B1 with argument " + x.getClass().getName());
        }
        public void invoke(A1 x) {
            System.out.println("Invoking method A1 on B1 with argument " + x.getClass().getName());
        }
        public void invoke(A2 x) {
            System.out.println("Invoking method A2 on B1 with argument " + x.getClass().getName());
        }

    }

    class B2 extends B1{
        public void invoke(A x) {
            System.out.println("Invoking method A on B2 with argument " + x.getClass().getName());
        }
        public void invoke(A1 x) {
            System.out.println("Invoking method A1 on B2 with argument " + x.getClass().getName());
        }
        public void invoke(A2 x) {
            System.out.println("Invoking method A2 on B2 with argument " + x.getClass().getName());
        }
    }

В этом примере выводится

Invoking method A on B2 with argument A2
Done!!!

, что означает A) - этоправильный ответ.

Почему это означает?

Хорошо ... потому что:
1) вызывается метод из класса B2 (как указано в выходных данных), а B2 - это тип времени выполненияleft (тип времени компиляции left равен B).
2) вызывается метод с параметром A (обратите внимание, что A является типом времени компиляции right), даже если тип времени выполненияright - это А2.Тип времени компиляции right - это просто тип, с которым объявлено right, т.е. A. Тип времени выполнения right - это фактический тип аргумента, то есть A2 (см. Вывод, там написано with argument A2).

0 голосов
/ 01 июня 2019

Java имеет A , она называется single dispatch :

  • перегрузка метода выбирается компилятором во время компиляции (соответствуеттип времени компиляции right для методов, предлагаемых типом времени компиляции left)
  • вызов метода происходит для типа времени выполнения left - поскольку методы не исчезают, left безусловно, есть метод с той же сигнатурой, которая была выбрана во время компиляции.Это действие считается «рассылкой», и поскольку оно зависит только от left (во время выполнения), оно «одиночное».

Супер простая демонстрация с использованием встроенных println(Object) и println(char[]):

char c[]={'a','b','c'};
System.out.println(c);
Object o=c;
System.out.println(o);

Это приводит к примерно как

abc
[C@1540e19d

Первая строка показывает, что println(char[]) объединяет массив символоввторая строка показывает, что точно такой же массив (можно добавить некоторую проверку, такую ​​как println(o==c);), переданную как Object во время компиляции, приводит к вызову перегрузки println(Object), независимо от типа среды выполнения.

B и C , вероятно, не существуют.

D вызывается многократная отправка , когда сигнатура методатакже выбирается во время выполнения с использованием фактического типа времени выполнения аргументов, и выбранный метод вызывается для типа времени выполнения left.Java не поддерживает это по умолчанию, это может быть реализовано с использованием отражения, вот пример с одним аргументом:

public static void trickyprintln(Object o) throws Exception {
    System.out.getClass().getMethod("println",o.getClass()).invoke(System.out,o);
}

public static void main (String[] args) throws Exception {
    char c[]={'a','b','c'};
    trickyprintln(c);
    Object o=c;
    trickyprintln(o);
}

Этот результат в

abc
abc

, поскольку println выбирается вручную, используя тип аргумента во время выполнения.Так что это можно сделать, если кому-то это действительно нужно в Java, но это не происходит автоматически.

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