В конструкторе класса cat public cat

Обновлено: 07.08.2022

Completely new to this forum as well as programming in Java. I've seen the other threads about this problem but it hasn't helped me, maybe it should've and I've just missunderstood it due to my so far shitty programmingvocabulary. Anywasy- to the problem;

Errorcode: Implicit super constructor Animal() is undefined. Must explicitly invoke another constructor

3 Answers 3

So you defined a class hierarchy where a Cat inherits Animal. What Java does when you create a Cat is that it creates a new instance of Cat. What Java actually does under the hood is:

  1. It calls the Cat constructor (which you have provided)
  2. Because Cat inherits from Animal it then also wants to call the Animal constructor. By default it calls the parameterless constructor. However, you have provided only a constructor for Animal that accepts a String. That's why it's complaining.

To fix it you can either provide a parameterless constructor

Or you can call the Animal constructor and pass it a name directly

The problem lies in that the constructor in Cat is attempting by default to call on the default constructor for Animal which by defining your constructor in Animal you have removed. Constructors of classes that extend some other class will automatically call on the default constructor of their superclass even if you don't explicitly write it in.

So your code should look something like this

The super(name) call here calls on the constructor we have defined for Animal as the super refers to the class than Cat extends from.

This is Error is caused by the constructor of your subclass implicitly calling on the default constructor of your base class

Your code is actually doing this:

Because you have defined a constructor in your base class, Animal , the default constructor no longer existences. So you need can do one of two things:

Add a default constructor that does nothing (or does helps you build your object without the need of passing in any arguments

Or call the base class constructor you did create and modify your subclass constructor to do whatever extra is needed for that subclass.

Something you should think about, when creating subclasses, is the usefulness of inheritance. Having a base class that can do general actions and setup makes it so that subclasses should only do what's unique to them.

If a base class is being used as a label instead of a shared functionality, then it might be best to make the base class an interface. When it comes to constructors you should have any general setup be done in the base class constructor and then set fields that are unique to the subclass in the subclass constructor.

This would set the private variables name and legs on a super class of Cat and make the constructor for Cat only perform actions that relate it's fields i.e. setting the level of cuteness for the Cat object. Also note that you can't call code before you call the super constructor in your subclass constructor. If you do, you will end up with another error.

Но я так не хочу. Можно ли как то переопределить конструктор в дочернем классе? Или это бред и нужно действовать по другому? Полный код ниже.

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

@ArtemKonovalov исправил формулировку вопроса. И скажите, за одно, пожалуйста, чем отличается Animal cat = new Cat("Кошка"); от Cat cat2 = new Cat("Кошка 2"); ? Результат вывода одинаков

4 ответа 4

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

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

первое правило:

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

то все равно в итоге на выходе получим

Но (. ), однако, второе правило:

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

  • В родительском классе у вас есть конструктор с параметрами (не дефолтный), а значит компилятор дефолтный конструктор сам не сгенерирует.
  • Класс наследник с дефолтным конструктором будет искать дефолтный конструктор в родителе, но его там нет (см. первый пункт почему)
  • Соответсвенно, для того, чтобы что-то сделать в дефолтном конструкторе наследника нужно определить дефолтный конструктор родителя

Ого как все интересно. Спасибо большое, теперь понятнее, буду вникать. А отличие Animal cat = new Cat("Кошка"); от Cat cat2 = new Cat("Кошка 2"); не подскажете? Мне чуть ниже ответили и как я понял, то если я пишу первый вариант, то мне доступно все, что я написал в Cat и Animal, а если второй, то только то, что я написал в Cat, а переменные и методы класса Animal уже не доступны?

@Grundy если только так. хотя если будет по-другому, тогда нужно super будет вызывать. А если super вызвать, то нельзя this вызвать. А-а-а-а-а-а, пристрелите меня))

Что мешает дописать в конструкторе класса потомка вывод того что было создано:

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

"А отличие Animal cat = new Cat("Кошка"); от Cat cat2 = new Cat("Кошка 2"); " - если вы изучаете ООП, то это тема уже Полиморфизма. Вкратце, классы , как вы помните это структуры (типы данных) с методами.Как говорит Брюс Эккель в Философия java - "..Везде, где видите класс понимайте тип и наоборот" Создавая классы вы создаете свои типы данных. Вы создали 2 типа данных Animal и Cat. Первая переменная cat типа Animal, а вторая cat2 типа Cat. Но так как класс Cat является потомком(extends) класса Animal, мы можем использовать полиморфизм. Вкратце, полиморфизм это - "возможность работать с несколькими типами так, как будто это один и тот же тип и в то же время поведение каждого типа будет уникальным в зависимости от его реализации." Пример, У вас могут быть различный потомки Animal - Dog, Fox, Wulf, Bair и тд и тп, и все их можно объявить и обработать как Animal. Например создать массив Animal animals[] и внутри хранить экземпляры и Dog и Fox и чего угодно, что является (extends) Animal.

Ага! Вон оно как. 5 минут назад наткнулся на канал Якова Файна, смотрю ролик на эту тему, спасибо) Слышал раньше о полиморфизме, но думал, что не скоро наткнусь, а оно сплошь и рядом..

На самом деле не зацикливайтесь на теории без практики. Не любил всегда эти примеры абстрактные Animal. Применение наследования(расширения или реализации) уже дело скорее архитектуры. Врядли вы будете проектировать класс Animal. Также могу вам посоветовать книгу Философия Java. must read для java программиста.

Посмотри на этот код и попробуй догадаться, что с нашей программой не так. На протяжении двух часов в нашей программе существовал кот без имени и возраста! Конечно, это в корне неверно. В базе данных ветеринарной клиники не должно быть котов без информации о них. Сейчас мы отдаем это на откуп программиста. Не забудет он указать имя и возраст — все будет ок. Забудет — в базе будет ошибка, неизвестные коты. Как нам решить эту проблему? Надо каким-то образом запретить создавать котов без имени и возраста.

Посмотри на этот код и попробуй догадаться, что с нашей программой не так. На протяжении двух часов в нашей программе существовал кот без имени и возраста! Конечно, это в корне неверно. В базе данных ветеринарной клиники не должно быть котов без информации о них. Сейчас мы отдаем это на откуп программиста. Не забудет он указать имя и возраст — все будет ок. Забудет — в базе будет ошибка, неизвестные коты. Как нам решить эту проблему? Надо каким-то образом запретить создавать котов без имени и возраста.

Здесь нам на помощь приходят функции-конструкторы. Приведем пример:

Конструктор — это, по сути, шаблон для объектов класса. В данном случае мы указывем, что для каждого объекта cat должны быть указаны два аргумента — строка и число. Если мы теперь попытаемся создать безымянного кота — у нас это не получится.

Теперь, когда в классе есть конструктор, компилятор Java знает, как должны выглядеть объекты, и не позволяет создавать объекты без указанных в нем аргументов.

Теперь давай разберемся с ключевым словом this , которое ты видишь внутри конструктора. С ним тоже все просто. "this" по-английски — "этот, этого". То есть это слово указывает на конкретный предмет. Код в конструкторе

можно перевести почти дословно: "name для этого кота (которого мы создаем) = аргументу name, который указан в конструкторе. age для этого кота (которого мы создаем) = аргументу age, который указан в конструкторе."

После срабатывания конструктора можешь проверить, что нашему коту присвоились все нужные значения:

Вывод в консоль: Барсик 5

Когда конструктор отработал:

Внутри него по факту произошло следующее:

И объекту barsik (он и является this ) присвоились значения из аргументов конструктора. На самом деле, если не указать в классе конструкторы у него все равно будет срабатывать конструктор! Но как такое возможно? О_О Дело в том, что в Java у всех классов есть так называемый конструктор по умолчанию. У него нет никаких аргументов, но он срабатывает каждый раз при создании любого объекта любого класса.

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

Вывод в консоль: Создали кота!

Вот и подтверждение. Конструктор по умолчанию всегда незримо присутствует в твоих классах. Но тебе нужно знать еще одну его особенность. Дефолтный конструктор исчезает из класса, когда ты создаешь какой-то конструктор с аргументами. Доказательство этого, на самом деле, мы уже видели выше. Мы не смогли создать кота без имени и возраста, потому что определили конструктор для Cat : строка + число. Дефолтный конструктор сразу после этого исчез из класса. Поэтому обязательно запомни: если тебе в твоем классе нужно несколько конструкторов, включая пустой, его нужно создать отдельно. Например, наша ветеринарная клиника хочет делать добрые дела и помогать бездомным котикам, чьих имен и возраста мы не знаем. Тогда наш код должен выглядеть так:

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

В конструкторе можно присваивать значения и явно, а не только брать их из аргументов. Например, мы можем записывать всех уличных котов в базу данных под именем "Уличный кот номер. " :

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

Поменяем в нашем конструкторе аргументы имени и возраста местами.

Ошибка! Конструктор четко описывает: при создании объекта Cat ему должны быть переданы число и строка, именно в таком порядке. Поэтому наш код не срабатывает. Обязательно запомни это и учитывай при создании своих собственных классов:

конструкторы Java_vertex

Конструкторы - это специальные методы, которые вызывается при создании объекта . Они "конструируют" новый объект определенного класса.

Шаг за шагом

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

1. Вы создаете основное "тело" программы, прописывая метод main:

2. Допустим, Вам нужен объект класса Cat. Класс Cat у вас уже есть, и выглядит он так:

Вы пишете строку, которая должна создать объект класса Cat:

3. В тот момент, когда программа приступает к созданию объекта cat1, она идет в class Cat:


Тут-то и появляется необходимость в конструкторах. Ведь в первую очередь Java ищет именно конструкторы, которые укажут, как именно создавать объект.


Но в нашем классе есть только геттеры и сеттеры - никаких конструкторов! Что же делать? Теперь объект не создастся?

Создастся, конечно. А все потому, что по-настоящему конструктор все равно присутствует - просто он явно не указан. Теперь, давайте посмотрим как создавать конструкторы явно, и какими они вообще бывают.

Явные и неявные конструкторы

Существуют два вида конструкторов - явные и неявные. Вы уже знаете, что, даже если ничего не прописать в коде класса, Вы все равно сможете "сконструировать" объект этого класса. Но, если все и так работает, зачем их вообще писать? Какие преимущества это дает?

Преимущество 1. Контроль над вводом данных.

Сначала, дайте посмотрим на изображение. Какие отличия Вы видите?

конструкторы Java_vertex

Если Вы заметили, что у всех трех классов разное количество параметров в конструкторе - Вы были правы:

конструкторы Java_vertex

Явно прописывая конструктор, Вы получаете возможность регулировать, какие параметры и в каком количестве нужно задать для создания объекта определенного класса.

Код№1 - класс Cat - скорее всего, был создан с использованием неявного конструктора. Он не просит никаких параметров.

Код№2 - класс Scanner - уже использует явно описанный конструктор. Он требует один параметр - и без него создать объект невозможно.

Код№3 - класс Dog - тоже использует явно описанный конструктор. Но тут, как мы видим, требуется уже три параметра - имя ("Шарик"), порода ("мопс") и возраст собаки (2 года).

Преимущество 2. Меньше строчек кода.

Вы заметили, как конструктор уменьшает количество строк в коде? Сравните:

Одной из проблем Java является ее многословность и объем необходимого стандартного кода. Это общеизвестно.

Давайте рассмотрим простой класс Cat на Java. Мы хотим, чтобы каждый объект Cat имел следующие атрибуты (поля):

Довольно просто, верно? Теперь давайте посмотрим на код в Java. Для простоты, давайте сделаем наш класс immutable (неизменным) — без сеттеров, мы все настроим в нашем конструкторе.

Это уже довольно длинно, не так ли?

Но станет хуже. Мы также хотим иметь некоторую базовую реализацию equals() и hashCode().

Мы уже закончили? Не совсем, нам еще понадобится хороший метод toString():

И наконец мы все сделали. Это около пятидесяти строк кода! Это довольно мучительно писать (хотя ваша IDE может помочь здесь) и трудно читать. Что еще хуже, трудно найти дополнительную функциональность (например, новые методы) в этом шаблонном коде.

В этих пятидесяти строках есть только три строки, которые действительно интересны и несут некоторую информацию:

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

В Java вы часто используете классы, которые просто хранят данные, как наш Cat. Реализация всегда почти одинакова — набор полей, геттеров, equals(), hashCode() и toString(). Часто бывает полезно иметь их неизменными, если это возможно, что имеет много преимуществ. Но писать и читать такие классы — это много работы, так как в них много кода. И это подвержено ошибкам. Кто знает, правильный ли ваш код для hashCode() и equals()?

Records

Java 14 пытается решить эту проблему, вводя новый тип под названием Record, он описан в JEP 359: Records (Preview).

Тот же класс длиной 50 строк из приведенного выше примера можно записать в виде записи, подобной этой:

Код намного меньше, верно?

Функциональность такая же, как в нашем предыдущем примере — у нас есть:

  • Неизменный класс с тремя полями
  • Конструктор присваивает эти поля
  • Геттеры
  • equals(), hashCode() и toString()

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

Вы можете видеть, что код в значительной степени совпадает с нашим старым Cat. Заметным исключением является то, что методы получения для сгенерированных полей именуются не так, как обычно — вместо getColor() есть только color().

Также класс расширяет java.lang.Record.

Реализация equals() считает две записи равными, если они имеют одинаковый тип и имеют одинаковые значения. Реализация toString() печатает нашу запись следующим образом:

Хотя эти методы предоставляются автоматически, их можно переопределить, если это необходимо.

Ограничения

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

  • Записи не могут расширять любой класс, хотя они могут реализовывать интерфейсы.
  • Записи не могут быть абстрактными.
  • Записи неявно являются final; они не могут быть унаследованы
  • Вы можете объявить дополнительные поля в теле записи, но только если они статичны

Добавление методов

Хотя записи в основном используются как простые носители данных, вы можете объявить свои собственные методы. Конечно, поскольку записи являются неизменяемыми, вы не можете изменять никакое состояние, но оно все равно может быть полезным. Например:

Вы также можете добавить статические методы.

Пользовательские (Custom) конструкторы

По умолчанию новые записи содержат только конструктор, которому нужны все поля записи в качестве параметров. Например, наш класс Cat с тремя полями должна быть построен так:

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

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

Конструктор со всеми полями генерируется для нас автоматически. Но иногда вам нужно выполнить там некоторую пользовательскую логику. Например, проверка ввода. Вы можете объявить самостоятельно, если вам необходимо, конструктор со всеми полями:

Если вы переопределяете конструктор со всеми полями, указанными в записи (канонический конструктор), вы можете использовать объявление без записи параметров. Они все еще доступны для использования, но код будет короче.

Интроспекция во время выполнения

В java.lang.Class добавлены два новых метода, которые имеют функциональность, связанную с записями.

Первый называется isRecord(). Это довольно просто, вы можете просто проверить, является ли какой-то объект записью или нет:

Другой является getRecordComponents(). Вы бы назвали это так же, как в примере выше. Возвращает список java.lang.reflect.RecordComponent. В основном это список всех полей, которые есть в записи с такой информацией, как:

Попробуйте сами!

Если вы хотите попробовать эту функцию самостоятельно, вы уже можете это сделать, хотя Java 14 еще не выпущена (по состоянию на 2/2020).

Preview feature (Превью возможности)

Функциональность записей (Records) доступна в Java 14. Однако в настоящее время только в качестве предварительного релиза. Что это означает?

Превью возможности языка и VM — это новая функция платформы Java SE, которая полностью специфицирована, реализована, но в то же время определена как временная. Она включается в выпуск JDK для получения обратной связи с разработчиками на основе реального использования; это может привести к тому, что она станет постоянной в будущей платформе Java SE.

Перед следующим выпуском функции JDK будут проанализированы сильные и слабые стороны функции в реальном мире, чтобы решить, имеет ли функция долгосрочную роль в платформе Java SE и, если да, нуждается ли она в уточнении. Следовательно, функции могут быть предоставлены окончательный и постоянный статус (с уточнениями или без них), или пройти дополнительный период предварительного просмотра (с уточнениями или без них), либо они могут быть удалены.

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

Чтобы попробовать эту функцию самостоятельно, вам нужно установить JDK 14.

Настройка IntelliJ IDEA

В IntelliJ IDEA вы можете включить функции Preview feature в меню File → Project Structure.


Чтобы использовать записи в IntelliJ IDEA, вам потребуется версия 2020.1 и более поздняя. По состоянию на 2/2020 она доступна как сборка по программе предварительного доступа (Early Access Program build). В настоящее время IDEA имеет базовую поддержку для записей, но полноценная поддержка должна быть доступна в релиз версии.

Ручная компиляция

Альтернативный вариант — вы собираете проект вручную. Тогда вам нужно предоставить следующие параметры для javac:

Это для компиляции. Во время выполнения вы просто предоставляете --enable-preview

Читайте также: