Java. Можете ли вы переопределить класс без вызова конструктора родительского класса?

У меня есть такой класс:

public class BaseClass
{
  public BaseClass(URL url, String something, String whatever)
  {
    // Do some stuff with URL, something and whatever
  }

  public List ImportantFunction()
  {
    // Some important stuff here
  }
}

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

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

super(url, something, whatever);

Можно ли расширить базовый класс, но иметь совершенно другой конструктор? Я вообще не хочу, чтобы конструктор BaseClass вызывался...


person Jake Wilson    schedule 31.01.2012    source источник


Ответы (4)


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

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

Нет никакого способа обойти это, если не использовать JNI для взлома JVM.

person Borealid    schedule 31.01.2012
comment
Допустим, есть класс, который вы хотите настроить. И скажем, этот класс откуда-то из Интернета. Очевидно, что простое редактирование исходного кода для его настройки кажется плохой идеей. Поэтому вместо этого вы расширите класс и сделаете настройки. Таким образом, если новая версия класса будет выпущена в сети, вам не придется заново вносить все изменения в код. Вы просто расширяете его своим пользовательским классом. Вы говорите, что если кто-то хочет настроить класс, они ВЫНУЖДЕНЫ вызывать конструктор родительского класса? - person Jake Wilson; 31.01.2012
comment
@Jakobud Если класс final, вы не можете создать его подкласс, а если у него нет конструктора, который вы хотите вызвать, вы не можете его использовать. Вот как работает Java - это не похоже на Python, где вы можете исправить ошибку на месте. - person Borealid; 31.01.2012
comment
@JakeWilson ... Вы можете сделать свой конструктор по умолчанию private, и в этом случае вы уверены, что его НЕЛЬЗЯ использовать. Однако, как говорит @Borealid, вы должны вызывать A-constructor. - person will; 14.06.2017

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

public BaseClass(){ }

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

person sethu    schedule 31.01.2012
comment
Итак, в конечном итоге я собираюсь изменить код BaseClass в любом случае? Этот класс не мой код. Я пытаюсь настроить его, не меняя сам код. Вы говорите, что я мог бы просто изменить его код? - person Jake Wilson; 31.01.2012
comment
Если вам нужно расширить BaseClass, вам нужно либо вызвать уже определенный конструктор, либо определить новый конструктор по умолчанию. К сожалению, другого пути нет. - person sethu; 31.01.2012
comment
Можно ли сказать, что BaseClass был написан плохо, потому что у него нет пустого конструктора по умолчанию? Потому что если бы это было так, то я мог бы расширить его и позволить этому пустому конструктору работать и знать, что он ничего не сделает. - person Jake Wilson; 31.01.2012

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

public class ChildClass extends BaseClass {
    public ChildClass(URL url, String something, String whatever) {
        // implicit call to the Parent's default constructor if next line is commented
        super(); // explicit call to the default constructor of ParentClass

        // now do stuff totally specific to your ChildClass here
    }
 }
person anubhava    schedule 31.01.2012
comment
Если у вас есть конструктор по умолчанию в родительском классе, вызов super() подразумевается и не требуется. - person Jeshurun; 31.01.2012
comment
Определенно не требуется, я просто хотел подчеркнуть тот факт в комментариях, что код может делать неявный или явный вызов конструктора ParentClass по умолчанию. - person anubhava; 31.01.2012

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

  1. Переместите весь код конструктора в защищенный метод в BaseClass, скажите что-то вроде protected void init(URL url, String something, String whatever){\\constructor code}
  2. Вызвать этот метод из конструктора

    public BaseClass (URL-адрес, строка что-то, строка что-то) { init (URL-адрес, что-то строка, что-то строка); }

  3. Переопределите этот защищенный метод в подклассе.

person Jeshurun    schedule 31.01.2012
comment
Я новичок в Java, но кажется глупым, что вы не можете расширить класс, не вызывая его конструктор. Весь смысл расширения классов в том, чтобы иметь возможность добавлять или изменять функциональность базового класса. Но если вы вынуждены вызывать базовый конструктор, то какой в ​​этом смысл??? - person Jake Wilson; 31.01.2012
comment
@Jakobud: потому что состояние объекта несовместимо во время вызова конструктора и может привести к неожиданному поведению. Объяснение см. в этом ответе. - person Jeshurun; 31.01.2012