Java: выяснить, была ли функция вызвана с помощью varargs или массива - PullRequest
7 голосов
/ 25 марта 2011

Есть ли способ узнать, была ли функция Java (или конструктор), которая принимает varargs, фактически вызываться с помощью varargs или с массивом?

Скажите, что у меня есть следующее:

public class MyCompositeObjects {

    MyObject[] objects;

    MyCompositeObjects(MyObjects... objects) {
        this.objects = Arrays.copyOf(objects,objects.length);
        // or just: this.objects = objects; ?
    }

    // ...
}

Конструктор может быть вызван с одним аргументом MyObject[], который может измениться позже, и если я не скопирую массив в конструкторе, эти изменения будут применяться и к переменной-члену objects, верно?Однако, если конструктор вызывается с несколькими MyObject с, нет другой ссылки на массив *, чтобы изменить его позже вне класса, поэтому я мог бы назначить его напрямую.Могу ли я сказать внутри конструктора (или вообще любой функции, которая принимает varargs), как она была вызвана?

* nb: Есть ли для этого конкретное имя?Это просто анонимный массив?

Ответы [ 2 ]

9 голосов
/ 25 марта 2011

Нет, вы не можете.Он должен быть полностью прозрачным - этот код:

new MyCompositeObjects(a, b);

в точности эквивалентен

new MyCompositeObjects(new MyObjects[] { a, b });

Если вы можете доверять своим абонентам, чтобы они поступали правильно,вы всегда можете создать два статических метода и сделать конструктор закрытым:

public static MyCompositeObjects createWithCopy(MyObjects[] values) {
    return new MyCompositeObjects(Arrays.copyOf(values, values.length));
}

public static MyCompositeObjects createWithoutCopy(MyObjects... values) {
    return new MyCompositeObjects(values);
}

private MyCompositeObjects(MyObjects[] values) {
    this.objects = values;
}

Обратите внимание, что версия «с копией» не использует varargs, что должно помочь пользователям использовать правильную версию.

4 голосов
/ 25 марта 2011

Единственный способ узнать это - проанализировать код.Это потому, что varargs по сути является функцией времени компиляции и не меняет способ работы программы.

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

Кстати: вы можете сделать следующее.

MyCompositeObjects(MyObjects o1, MyObjects... objects) {

MyCompositeObjects(MyObjects[] objects) {

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

Другой вариант - использовать статическую фабрику.

private MyCompositeObjects(MyObjects[] objects) {
   this.objects = objects;
}

MyCompositeObjects create(MyObjects... objects) {
    return new MyCompositeObjects(objects.close());
}

MyCompositeObjects createNotCopied(MyObjects... objects) {
    return new MyCompositeObjects(objects, false);
}

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

...