Java не работает переопределение

Переопределение Java не работает

Я новичок в Java, я использовал PHP, C ++ и Lua и никогда не сталкивался с этой проблемой, я сделал два класса только для тренировки Facto и MyFacto , первый действительно находит факториал, а второй факториал нужно находить не сложением, а умножением. Не вините меня за глупый и бессмысленный код, я просто тестирую и пытаюсь разобраться в Java.

Я думал, что результат должен быть 15 и 120, но я получил 15 и 15. Почему это происходит? Связано ли это с тем, что метод calc() не переопределяется, и он использует метод run() из класса Facto ? Как я могу это исправить или как правильно переопределить что-то подобное?

2 ответа

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

    public позволяет любому классу Java видеть поле / функцию, если это возможно.

или отсутствие явного модификатора позволяет любому объекту Java (но не подклассам) видеть поле / функцию, если они находятся в одном каталоге или пакете.

  • protected позволяет объявленному классу и всем другим подклассам получить доступ к этому полю / функции, а также к любому классу в том же каталоге / пакете.
  • private позволяет только объявленному классу получить доступ к этому полю / функции.
  • Чтобы расширить то, что сказал @Makoto, вы столкнулись с проблемой, потому что метод calc() объекта Facto не имеет доступа к методу run() объекта MyFacto , поэтому он используя собственный метод run() . Изменение их обоих на protected вместо private должно помочь.

    Кроме того, вам, вероятно, следует научиться использовать аннотацию @Override . Рекомендуется ставить его выше любого метода, который вы переопределяете. Таким образом, если вы что-то опечатаете или параметры не совпадают, вы получите предупреждение. Кроме того, это дает понять вам и / или читателю. Например:

    Источник

    Все о переопределении в Java

    У нас на этой неделе практически юбилей — стартует пятая группа «Разработчик Java», а это значит, что мы снова делимся всякими полезностями.

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

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

    Что такое полиморфизм?

    Полиморфизм позволяет вам определить один интерфейс и иметь для него несколько реализаций. Это один из основных принципов объектно-ориентированного программирования. Слово «полиморфизм» буквально означает «состояние наличия многих форм» или «способность принимать разные формы». При применении к объектно-ориентированным языкам программирования, таким как Java, он описывает способность языка обрабатывать объекты разных типов и классов через единый, однородный интерфейс.

    Что такое полиморфизм времени выполнения (или отправка динамического метода?)

    Переопределенный метод вызывается в соответствии с объектом, которому принадлежит метод, а не по типу ссылки.

    В чём польза полиморфизма времени выполнения?

    Статический или динамический полиморфизм?

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

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

    Читайте также:  Как настроить почтовый ящик аутлук

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

    Правила динамического полиморфизма

    Изменение сигнатуры метода

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

    Тип возврата метода

    Типы возвращаемых данных могут варьироваться в зависимости от методов, которые переопределяют друг друга, если типы возврата являются ссылочными типами. Java поддерживает ковариантные возвращения — специализацию типа возврата к подтипу. Объявление метода d1 с типом возврата R1 заменит возвращаемое значение метода d2 с возвращаемым типом R2 тогда и только тогда, когда выполняются следующие условия:

    • Если R1 void, то R2 является void.
    • Если R1 является примитивным типом, то R2 идентичен R1.
    • Если R1 является ссылочным типом, то: R1 является либо подтипом R2, либо R1 может быть преобразован в подтип R2 путем unchecked преобразования или
    • R1 = | R2 |

    Ковариантный тип возврата

    Возвращение коварианта означает, что при переопределении метода возвращаемый тип переопределяющего метода разрешен как подтип возвращаемого типа переопределенного метода.

    Чтобы прояснить это с помощью примера, общим случаем является Object.clone (), который объявляется для возврата типа объекта. Вы можете переопределить это в своем классе следующим образом:

    Переопределение статического метода (или) Связывание метода

    Связывание статических переменных

    Final и private методы

    Переопределение уровней доступа

    Переопределение с super()

    Переопределение с абстракцией

    Переопределение с исключениями

    Переопределение из внутренних приватных классов

    Переопределение и перегрузка

    Переопределение методов экземпляра против статических методов

    Переопределение методов экземпляра против статических переменных

    Конструктор с super()

    Переопределение другого и того же пакетов

    Правила ребенок-родитель: последствия переопределения

    Методы экземпляра предпочтительнее default методов интерфейса.

    Программы, содержащие комментарии для иллюстрации использования и последствий при переопределении, могут иметь некоторые CE и RE.

    Как всегда будем рады видеть ваши комментарии или вопросы.

    Источник

    Переопределение метода java equals () — не работает?

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

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

    я разрабатывал базовую корзину который может содержать ArrayList of Book объекты. В целях реализации addBook() , removeBook() и hasBook() методы тележки, я хотел проверить, если Book уже существовал в Cart . Так что я пошел —

    все работает отлично в тестировании. Я создаю 6 объектов и заполнить их данными. Сделайте много операций добавления, удаления, has() на Cart и все работает нормально. Я читал, что вы можете либо equals(TYPE var) или equals(Object o) но предположил, что раз он работает, это не имеет большого значения.

    затем я столкнулся с проблемой — мне нужно было создать Book объект только the ID в нем из книги класс. Никакие другие данные в него не вводились. В основном следующее:

    внезапно, к equals(Book b) способ больше не работает. Это заняло очень много времени, чтобы отследить без хорошего отладчика и предполагая Cart класс был правильно протестирован и правильный. После swaapping в equals() метод следующим образом:

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

    Источник

    Переопределение статического метода в Java

    В Java нельзя переопределять статические методы. Но почему работает следующий код:

    На печать выводится «B». Все выглядит так, как будто это переопределение. Потому что при перегрузке я должна была бы что-то изменить в сигнатуре метода. Но нет, я ничего не меняла.

    Аннотацию «override» не могу поставить над методом.

    2 ответа 2

    Начнем по порядку

    Переопределение метода:

    Переопределение метода (Method overriding) это возможность языка позволяющая подклассу или дочернему элементу классу обеспечивать специфическую реализацию метода, который уже реализовали в одном из супер-классов или родительском классе. Переопределение выглядит так:

    Переопределенный метод должен иметь тот же модификатор доступа что его родитель, принимать аргументы как его родитель, и иметь возвращаемый тип такой же как у его родителя
    Т.е.

    Сокрытие метода:

    Сокрытие методов, грубо говоря, представляет из себя «перекрытие» методом текущего класса, метода родительского класса. Выглядит это следующим образом:

    Сигнатуры методов этих двух классов идентичны, т.е. в классе родителе Animal есть public static void voice() и в классе-наследнике Dog есть public static void voice() . Следовательно вызов Dog.voice() будет вызывать метод определенный в классе Dog

    Важно отметить, что перекрытие требует таких же правил как и переопределение метода.

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

    Рассмотрим использование таких методов в своих классах

    1. Использование без схожего по сигнатуре метода

    Поскольку в классе-наследнике нет реализованного схожего по сигнатуре с родительским классом метода, то используется метод унаследованный от родительского класса

    1. Использование схожего по сигнатуре метода

    Поскольку теперь у класса Dog появился «свой метод» voice() он перекрывает метод унаследованный от Animal

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

    Хочу дополнить тем, что перекрытие работает не только с методами класса, но и с его полями. Небольшой пример:

    Источник

    Перегрузка и переопределение методов в Java

    Изучите основы перегрузки и переопределения методов в Java.

    Автор: baeldung
    Дата записи

    1. Обзор

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

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

    2. Перегрузка метода

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

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

    Если мы дали методам вводящие в заблуждение или двусмысленные имена, такие как multiply 2() , multiply 3() , multiply 4 (), , то это будет плохо спроектированный API класса. Здесь в игру вступает перегрузка методов.

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

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

    2.1. Различное количество аргументов

    Класс Multiplier в двух словах показывает, как перегрузить метод multiplier () , просто определив две реализации, которые принимают разное количество аргументов:

    2.2. Аргументы различных типов

    Аналогично, мы можем перегрузить метод multiply () , заставив его принимать аргументы разных типов:

    Кроме того, правомерно определить класс Multiplier с обоими типами перегрузки методов:

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

    Чтобы понять, почему – давайте рассмотрим следующий пример:

    В этом случае код просто не будет компилироваться из – за неоднозначности вызова метода – компилятор не будет знать, какую реализацию multiply() вызывать.

    2.3. Тип Продвижения

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

    Проще говоря, один данный тип неявно повышается до другого, когда нет соответствия между типами аргументов, переданных перегруженному методу, и конкретной реализацией метода.

    Чтобы более четко понять, как работает продвижение типов, рассмотрим следующие реализации метода multiply() :

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

    Давайте посмотрим быстрый модульный тест, чтобы продемонстрировать продвижение типа:

    И наоборот, если мы вызываем метод с соответствующей реализацией, продвижение типа просто не происходит:

    Вот краткое описание правил продвижения типов, которые применяются для перегрузки методов:

    • байт может быть повышен до short, int, long, float, или double
    • short может быть повышен до int, long, float, или double
    • char может быть повышен до int, long, float, или double
    • он может быть повышен до long, float, или double
    • long может быть повышен до float или double
    • float может быть повышен до double

    2.4. Статическая привязка

    Возможность связать конкретный вызов метода с телом метода называется связыванием.

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

    Компилятор может эффективно установить привязку во время компиляции, просто проверив сигнатуры методов.

    3. Переопределение метода

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

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

    Теперь давайте посмотрим, как использовать переопределение метода, создав простое отношение на основе наследования (“is-a”).

    Вот базовый класс:

    А вот надуманный подкласс:

    В приведенной выше иерархии мы просто переопределили метод accelerate () , чтобы обеспечить более точную реализацию подтипа Car.

    Здесь ясно видно, что если приложение использует экземпляры класса Vehicle , то оно также может работать с экземплярами Car , поскольку обе реализации метода accelerate () имеют одинаковую сигнатуру и один и тот же тип возвращаемого значения.

    Давайте напишем несколько модульных тестов для проверки классов Vehicle и Car :

    Теперь давайте посмотрим некоторые модульные тесты, которые показывают, как методы run() и stop () , которые не переопределены, возвращают равные значения для обоих Car и Vehicle :

    В нашем случае у нас есть доступ к исходному коду для обоих классов, поэтому мы можем ясно видеть, что вызов метода accelerate() на базовом экземпляре Vehicle и вызов accelerate() на экземпляре Car вернет разные значения для одного и того же аргумента.

    Таким образом, следующий тест демонстрирует, что переопределенный метод вызывается для экземпляра Car :

    3.1. Взаимозаменяемость Типов

    Основным принципом в ООП является принцип подстановки типов, который тесно связан с принципом подстановки Лискова (LSP) .

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

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

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

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

    3.2. Динамическая привязка

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

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

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

    4. Заключение

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

    Как обычно, все примеры кода, показанные в этой статье, доступны на GitHub .

    Источник

    Оцените статью