Производительность. Должен ли я избегать делегирования конструктора?

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

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

В качестве примера, это класс Vector3D, который я недавно создал:

public class Vector3D {

    public final int x, y, z;

    public Vector3D() {
        this(0, 0, 0);
    }

    public Vector3D(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

Получаю ли я выгоду от не вызова this(0, 0, 0) и просто установки переменных таким образом?

public class Vector3D {

    public final int x, y, z;

    public Vector3D() {
        this.x = 0;
        this.y = 0;
        this.z = 0;
    }

    public Vector3D(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

Ответы

Ответ 1

Main.java

package pokus1;

public class Main {

    public int m_a;
    public int m_b;

    public Main(int a, int b) {

        m_a = a;
        m_b = b;

    }

    public Main() {
        this(0,0);
    }

    public static void main(String[] args) {

        Main main = new Main();

    }

}

Выход Javap (javap -v Main.class) для pokus1.Main():

Вы видите инструкцию invokespecial на смещении 3? Это вызов pokus1.Main(int a,int b). Так что фундаментально да, более эффективно не вызывать второй конструктор. Но есть много оптимизаций в текущих реализациях JVM, таких как метод inlining, компиляция точно в срок и т.д., Поэтому я думаю, вам не нужно об этом думать, иначе вы можете думать о каждом вызове java, если это необходимо.

public pokus1.Main();
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0       
         1: iconst_0      
         2: iconst_0      
         3: invokespecial #24                 // Method "<init>":(II)V
         6: return        
      LineNumberTable:
        line 16: 0
        line 17: 6
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       7     0  this   Lpokus1/Main;

Ответ 2

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

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

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

Ответ 3

Как правило, нет никакой разницы, потому что компилятор только во времени строит короткие методы.

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