Почему у вас есть два конструктора с одной и той же подписью?

Каковы варианты использования двух конструкторов с одной и той же сигнатурой?

Изменить: вы не можете сделать это на Java, из-за чего Effective Java говорит, что вам нужен статический factory. Но мне было интересно, зачем вам это делать в первую очередь.

Ответ 1

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

Например, я мог бы одурачить себя мыслью о том, что мне нужно дать мои два класса-конструктора Point Point: один, который работает по X и Y, и по-разному, и радиан. Оба могут быть представлены как float.

Итак, я бы подумал, что мне нужны два конструктора с одинаковыми сигнатурами (float, float).

р. Блох указывает, что лучше сделать методы factory:


    public static Point newPointByDegreesAndRadians (float degrees, float radians);
    public static Point newPointByXandY (float x, float y);

Кстати, другой альтернативой методам factory является создание типов, которые несут контекст, отсутствующий в типах данных, например:


    public class CoordinatesXY {
       float X;
       float Y;
       ...
    }
    public class CoordinatesDegreesRadians {
       float degrees;
       float radians;
       ...
    }
    public Point (CoordinatesXY coordinates) { ... }
    public Point (CoordinatesDegreesRadians coordinates) { ... }

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

Ответ 2

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

Простым примером может быть класс Line.

Здесь один конструктор: public class Line(double x1, double y1, double x2, double y2)

Здесь другой: public class Line(double x1, double y1, double angle, double distance)

Первый конструктор определяет две конечные точки линии. Второй конструктор определяет одну конечную точку, а угол и расстояние до второй конечной точки.

Java не может различать два конструктора класса Line, true. Но есть веские причины для того, чтобы 2 или более конструктора имели одну и ту же подпись.

Ответ 3

Класс не может иметь двух конструкторов с одинаковой сигнатурой.

Из JLS:

8.8.2 Подпись конструктора

Это ошибка времени компиляции для объявления двух конструкторов с переопределяющими эквивалентами (§8.4.2) сигнатурами в классе. Ошибка компиляции для объявления двух конструкторов, чья подпись имеет такое же стирание (§4.6) в классе.

Ответ 4

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

Например, скажем, у вас был класс Person, который заботился о имени и месте рождения кого-то.

public Person(String name) { ... }
public Person(String placeOfBirth) { ... }

Очевидно, что это не сработает.

Вы должны использовать factory:

public static Person personWithName(String name) { ... }
public static Person personFromPlace(String placeOfBirth) { ... }

Очевидно, надуманный пример, но что общая идея...

Ответ 5

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

Ответ 6

@kunjaan - для такой идеи очень мало случаев, даже если есть технически обоснованный способ сделать это (что в Java нет - см. другие ответы).

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

Другим примером этого может быть конструктор, который будет реализовывать определенные вещи, используя более эффективный системный вызов, если текущая архитектура поддерживает этот системный вызов. Кстати, оба этих примера немного сложнее представить на Java, но их легче представить на С++ -land, но вы надеетесь получить общую идею.

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

function helper_initializer(signature for case 1) {

}
function helper_initializer(signature for case 2) {

}
function constructor() {
   // constructor logic here
   if (environmental_consdition() == 1) {
      this->helper_initializer(signature for case 1);
   } else {
      this->helper_initializer(signature for case 2);
   }
}