Что такое метод вложения?

Я пытался понять, что это на самом деле означает:

встроенная функция

В С++ функция-член, определенная в объявление класса. (2) Функция вызовите, что компилятор заменяет фактический код для функции. ключевое слово inline может использоваться для подсказки компилятор для выполнения встроенных расширение тела члена или nonmember.

рядный

Чтобы заменить вызов функции копией кода функции во время сборник.

Например, написано что-то вроде:

Когда метод является окончательным, он может быть встраиваемый.

Здесь: http://www.roseindia.net/javatutorials/final_methods.shtml

Можете ли вы привести мне пример или что-то или в основном помочь мне понять, что означает "оно может быть включено".

Спасибо.

Ответ 1

Inlining - это оптимизация, выполняемая компилятором Java Just-In-Time.

Если у вас есть метод:

public int addPlusOne(int a, int b) {
  return a + b + 1;
}

который вы вызываете так:

public void testAddPlusOne() {
  int v1 = addPlusOne(2, 5);
  int v2 = addPlusOne(7, 13);

  // do something with v1, v2
}

компилятор может решить заменить вызов функции телом функции, поэтому результат будет выглядеть примерно так:

public void testAddPlusOne() {
  int v1 = 2 + 5 + 1;
  int v2 = 7 + 13 + 1

  // do something with v1, v2
}

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

Это можно сделать только для не виртуальных функций. Подумайте, что произойдет, если метод будет переопределен в подклассе, а тип объекта, содержащий этот метод, неизвестен до времени выполнения... как компилятор узнает, какой код будет копироваться: тело метода базового класса или подкласс метод тело? Поскольку все методы виртуальны по умолчанию в Java, вы можете явно отмечать те, которые не могут быть переопределены как final (или помещены в класс final). Это поможет компилятору понять, что этот метод никогда не будет переопределен, и он безопасен для встроенных. (Обратите внимание, что компилятор иногда может также выполнить это определение для не конечных методов.)

Кроме того, обратите внимание на слово может в цитате. Окончательные методы не гарантируются. Существуют различные способы гарантировать, что метод не способен быть встроенным, но не может заставить компилятор встроить. Это почти всегда будет лучше, чем вы, в любом случае, когда инкрустация поможет или повредит скорость полученного кода.

См. wikipedia для хорошего обзора преимуществ и проблем.

Ответ 2

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

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

Ответ 3

Скажем, у вас есть класс, который выглядит так:

public class Demo {
    public void method() {
        // call printMessage
        printMessage();
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}

Вызов printMessage может быть "inlined" следующим образом:

public class Demo {
    public void method() {
        // call printMessage
        System.out.println("Hello World"); // <-- inlined
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}

(Это фактически не выполняется на уровне Java (даже на уровне байт-кода), но во время JIT-компиляции, но приведенный выше пример иллюстрирует концепцию inlining.)

Теперь рассмотрим, что произойдет, если метод printMessage был перегружен другим классом, например:

class SubDemo extends Demo {
    public void printMessage() {
        System.out.println("Something else");
    }
}

Теперь, если компилятор заключил вызов в Demo.printMessage, он будет зависеть от System.out.println("Hello World");, который был бы неправильным, если объект был фактически экземпляром SubDemo.

Однако, если метод был объявлен final, это ни в коем случае не было бы так. Если метод является "окончательным", это означает, что он никогда не может быть переопределен новым определением, поэтому безопасно его встроить!