Зачем вам два конструктора с одинаковой подписью? - PullRequest
10 голосов
/ 16 мая 2010

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

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

Ответы [ 6 ]

15 голосов
/ 16 мая 2010

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

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

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

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


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

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


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

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

11 голосов
/ 16 мая 2010

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

Простым примером будет класс 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, верно. Но есть веские причины для двух или более конструкторов иметь одинаковую подпись.

5 голосов
/ 16 мая 2010

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

Из JLS :

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

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

3 голосов
/ 16 мая 2010

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

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

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

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

Вы должны использовать фабрику:

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

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

2 голосов
/ 16 мая 2010

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

1 голос
/ 16 мая 2010

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

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

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

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

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);
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...