Финальные методы встроены?

Являются ли финальные методы Java автоматически встроенными?

Многие книги говорят да, многие книги говорят нет!!!

7 ответов

Решение

Интересный вопрос, побудивший меня изучить его дальше. 2 интересных замечания, которые я нашел -

  • 1 комментарий, что автоматическое встраивание является ошибкой:

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

Чтобы понять почему, предположим, что компилятор просматривает класс A и подкласс B, а также подкласс C и видит последний метод в A, который он вставляет в C. Но тогда во время выполнения версии, загруженные для A и B, различаются, и метод не финальный в A и переопределенный в B. Тогда C использует неверно встроенную версию. T

И, немного более авторитетно, из солнечной статьи, написав, что методы можно оставить виртуальными,

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

Вот более прямая ссылка на механизм.

Встраивание методов выполняется компилятором JIT, а не javac.

Современные JIT-компиляторы (включая Hotspot) часто могут включать даже не финальные методы, "при необходимости" отменяя оптимизацию. Они в основном очень умные.

Короче говоря: это полностью зависит от ВМ. На мой взгляд, вы должны сделать ваши методы окончательными или не основанными на том, что производит чистый код, а не на производительности. Я лично фанат "дизайна для наследования или запрета", но это другое обсуждение:)

Если вы имеете в виду "они встроены во время компиляции", то нет, они не будут.

Однако статические конечные поля иногда могут быть встроены компилятором, например, примитивами и строками.

final больше о добавлении семантики в дизайн, чем о том, чтобы сказать компилятору или виртуальной машине что-то встроить. Современные виртуальные машины встроены гораздо больше, чем одни только конечные методы, так что это не очень хорошая причина для использования final или попытайтесь предсказать слишком много об оптимизации времени выполнения.

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

Как сказал Джон, встраивание выполняется (когда это необходимо) компилятором JIT не на уровне генерации байт-кода. Также обратите внимание, что иногда встраивание может привести к снижению производительности, потому что это может создать ситуацию, когда один и тот же код присутствует несколько раз в кэше cpu l1, освобождая место для другого кода. Отсутствие кэша L1 может повлиять на производительность больше, чем переход к кешированной функции.

Константы (или финальная статическая переменная) встроены.

Смотрите это, чтобы проверить

public class InlineTest {
    final static int add(int x, int y) {
        return x + y;
    } 
}


public class Main {

        static final int DIVISOR = 7;

        static void main(String[] args){
            final int a = new Integer(args[0]);
            final int b = new Integer(args[1]);

            if (InlineTest.add(a, b) % DIVISOR == 0)
                System.exit(InlineTest.add(a, b));

            System.out.print("The sum is " + InlineTest.add(a, b));

        }
}

Это переводится в:

 0 new #2 <java/lang/Integer>
 3 dup
 4 aload_0
 5 iconst_0
 6 aaload
 7 invokespecial #3 <java/lang/Integer/<init>(Ljava/lang/String;)V>
10 invokevirtual #4 <java/lang/Integer/intValue()I>
13 istore_1
14 new #2 <java/lang/Integer>
17 dup
18 aload_0
19 iconst_1
20 aaload
21 invokespecial #3 <java/lang/Integer/<init>(Ljava/lang/String;)V>
24 invokevirtual #4 <java/lang/Integer/intValue()I>
27 istore_2
28 iload_1
29 iload_2
30 invokestatic #5 <com/gamasoft/InlineTest/add(II)I>
33 bipush 7
35 irem
36 ifne 47 (+11)
39 iload_1
40 iload_2
41 invokestatic #5 <com/gamasoft/InlineTest/add(II)I>
44 invokestatic #7 <java/lang/System/exit(I)V>
47 getstatic #8 <java/lang/System/out Ljava/io/PrintStream;>
50 new #9 <java/lang/StringBuilder>
53 dup
54 invokespecial #10 <java/lang/StringBuilder/<init>()V>
57 ldc #11 <The sum is >
59 invokevirtual #12 <java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;>
62 iload_1
63 iload_2
64 invokestatic #5 <com/gamasoft/InlineTest/add(II)I>
67 invokevirtual #13 <java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;>
70 invokevirtual #14 <java/lang/StringBuilder/toString()Ljava/lang/String;>
73 invokevirtual #15 <java/io/PrintStream/print(Ljava/lang/String;)V>
76 return

Вы можете видеть, что статическая функция InlineTest.add была вызвана несколько раз с invokestatic

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

В любом случае, это будут очень маленькие и простые методы, которые будут встроены, и даже не все из них.

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