Они могут быть разных типов, таких как int, String, custom types и так далее.
Top level class (Обычный класс):
Nested class (Вложенный класс):
К классам верхнего уровня модификатор static неприменим.
Класс называется вложенным (Nested class), если он определен внутри другого класса.
Вложенный класс должен создаваться только для того, чтобы обслуживать обрамляющий его класс.
Если вложенный класс оказывается полезен в каком-либо ином контексте, он должен стать классом верхнего уровня.
Вложенные классы имеют доступ ко всем (в том числе приватным) полям и методам внешнего класса, но не наоборот. Из-за этого разрешения использование вложенных классов приводит к некоторому нарушению инкапсуляции.
Существуют четыре категории вложенных классов:
Static nested class
(Статический вложенный класс)
Это статические члены внешнего класса,
поэтому они могут существовать без экземпляра внешнего класса.
Member inner class
(Простой внутренний класс)
Это нестатические классы, объявленные внутри другого класса.
Они имеют доступ до всех членов внешнего класса, включая приватные.
Local inner class
(Локальный класс)
Это классы, объявленные внутри блока кода, обычно в методе.
Anonymous inner class
(Анонимный класс)
Это специальный тип локальных классов, которые не имеют имени.
Категории классов, за исключением первого, также называют внутренними (Inner class).
Внутренние классы ассоциируются не с внешним классом, а с экземпляром внешнего.
Static nested class | Member inner class | Local inner class | Anonymous inner class | |
---|---|---|---|---|
Из него видны: |
Из него (самого класса) видны: - статические свойства и методы OuterClassа (даже private). - статические свойства и методы родителя OuterClassа public и protected.
Из его экземпляра видны: - все (даже private) свойства и методы OuterClassа обычные и статические. - public и protected свойства и методы родителя OuterClassа обычные и статические.
|
- все (даже private) свойства и методы OuterClassа обычные и статические. - public и protected свойства и методы родителя OuterClassа обычные и статические.
|
- все (даже private) свойства и методы OuterClassа обычные и статические. - public и protected свойства и методы родителя OuterClassа обычные и статические. То есть те, которые видны в OuterClassе. |
- все (даже private) свойства и методы OuterClassа обычные и статические. - public и protected свойства и методы родителя OuterClassа обычные и статические.
|
Его видно: | - согласно модификатору доступа. | - согласно модификатору доступа. | - только в том методе где он определён. | - только в том методе где он определён. |
Может наследовать: |
- обычные классы. - такие же статические внутренние классы в OuterClassе и его предках. |
- обычные классы. - такие же внутренние классы в OuterClassе и его предках. |
- обычные классы. - внутренние классы в OuterClassе и его предках. - такие же локальные классы определённые в том же методе. |
Не может наследовать |
Может быть наследован: |
- любым классом: - вложенным - не вложенным - статическим - не статическим! |
- таким же внутренним классом в OuterClassе и его наследниках. | - таким же локальным классом определённом в том же методе. | Не может быть наследован |
Может имплементировать интерфейс | ДА | ДА | ДА | НЕТ |
Может содержать: |
- статические свойства и методы. - не статические свойства и методы. |
- только обычные свойства и методы (не статические). | - только обычные свойства и методы (не статические). | - только обычные свойства и методы (не статические). |
Вложенные классы используются для различных целей:
Статический вложенный класс в JAVA - это статический член внешнего класса, который может
существовать
независимо от экземпляра внешнего класса.
Они объявляются внутри другого класса и используют модификатор
static.
Статические вложенные классы применяются, когда:
Так как статический вложенный класс не требует экземпляра внешнего класса для его создания, вы можете создать столько экземпляров статического вложенного класса, сколько вам нужно или сколько позволяет память вашей системы.
Статический вложенный класс имеет прямой доступ только к статическим полям обрамляющего класса.
Простой внутренний класс, может обратиться к любому полю внешнего класса напрямую. В случае, если у вложенного класса уже существует поле с таким же литералом, то обращаться к такому полю следует через ссылку на его экземпляр.
Например: Outer.this.field.
Можно почитать: Вложенные классы в JAVA
Local inner class (Локальный класс) - это вложенный класс, который может быть декларирован в любом блоке, в котором разрешается декларировать переменные.
Как и простые внутренние классы (Member inner class) локальные классы имеют имена и могут использоваться многократно.
Как и анонимные классы, они имеют окружающий их экземпляр только тогда, когда применяются в нестатическом контексте.
Это вложенный локальный класс без имени, который разрешено декларировать в любом месте обрамляющего класса, разрешающем размещение выражений.
Создание экземпляра анонимного класса происходит одновременно с его объявлением.
В зависимости от местоположения анонимный класс ведет себя как статический либо как нестатический вложенный класс - в нестатическом контексте появляется окружающий его экземпляр.
Если речь об объектах разных классов - сколько позволяет память вашей системы.
Если об экземплярах конкретного класса, то каждое объявление анонимного класса ведет к созданию нового класса во время компиляции. т.е. один.
Перечисления представляют набор логически связанных констант.
Объявление перечисления происходит с помощью оператора enum, после которого идет название перечисления. Затем идет список элементов перечисления через запятую.
Каждый из них явно объявлен как открытый статический финальный член класса.
Это специальные методы, которые вызываются при создании объекта класса.
Имя конструктора должно совпадать с именем класса.
Они используются для инициализации полей класса.
Если у какого-либо класса не определить конструктор, то компилятор сгенерирует конструктор без аргументов - так называемый «конструктор по умолчанию».
Если вы создали конструктор с аргументами, то конструктор по умолчанию использоваться не будет (если он не создан).
Приватный (помеченный ключевым словом private, скрытый) конструктор может использоваться публичным статическим методом генерации объектов данного класса.
Также доступ к нему разрешен вложенным классам и может использоваться для их нужд.
Запрещает создание экземпляра класса вне методов самого класса, например, чтобы гарантировать существование только одного объекта определённого класса, предположим какого-то ресурса, например БД.
У конструктора по умолчанию отсутствуют какие-либо аргументы.
Конструктор копирования принимает в качестве аргумента уже существующий объект класса для последующего создания его клона.
Конструктор с параметрами имеет в своей сигнатуре аргументы (обычно необходимые для инициализации полей класса).
в JAVA конструкторы не наследуются, и поэтому они не могут быть переопределены в подклассах. Однако, подкласс может вызывать конструктор суперкласса с помощью ключевого слова super.
Перегрузка конструктора в JAVA это механизм, который позволяет классу иметь более одного конструктора, но с различными параметрами.
Перегруженные конструкторы отличаются друг от друга по числу параметров или по типу параметров. Компилятор Java использует эти различия для определения, какой из конструкторов следует вызывать при создании объекта.
Основной целью перегрузки конструктора является увеличение гибкости при создании объектов класса.
private(приватный): члены класса доступны только внутри класса.
default, package-private, package level (доступ на уровне пакета): видимость класса/членов класса только внутри пакета. Является модификатором доступа по умолчанию.
protected(защищённый): члены класса доступны внутри пакета и в наследниках.
public (публичный): класс/члены класса доступны всем.
Во время наследования возможно изменения модификаторов доступа в сторону большей видимости (для поддержания соответствия принципу подстановки Барбары Лисков).
Ключевое слово | Класс | Пакет | Наследник | Все |
---|---|---|---|---|
private | YES | NO | NO | NO |
- | YES | YES | NO | NO |
protected | YES | YES | YES | NO |
public | YES | YES | YES | YES |
Модификатор, применяемый к полю, блоку, методу, внутреннему классу.
Данный модификатор указывает на привязку субъекта к текущему классу.
Модификатор final может применяться к переменным, параметрам методов, полям и методам класса или самим классам.
Да
Объект статического класса не хранит ссылку на конкретный экземпляр внешнего класса.
Объект статического вложенного класса вполне может существовать сам по себе.
Статический вложенный класс может обращаться только к статическим полям и методам внешнего класса.
Объекты статического класса не содержат ссылок на объекты внешнего класса. А самих объектов мы можем создать сколько угодно.
Может ли быть абстрактный класс без абстрактных методов?
Могут ли быть конструкторы у абстрактных классов?
Сколько абстрактных методов должен и может содержать абстрактный класс?
Может ли абстрактный класс содержать обычные методы?
Сколько объектов абстрактного класса можно создать в программе?
Абстрактные классы в JAVA - это классы, которые не могут быть инстанцированы.
т.е., вы не можете создать объекты таких классов напрямую)
Создавать экземпляры самого абстрактного класса не разрешается.
Они обычно используются как базовые классы для других классов и могут выступать только предками для других классов.
Для обозначения используется модификатор abstract.
Абстрактные классы могут содержать как абстрактные методы, так и не абстрактные методы.
- Абстрактные методы - это методы, которые объявлены, но не реализованы в абстрактном классе.
Вместо того, чтобы предоставлять реализацию, абстрактные методы обычно заканчиваются точкой с запятой.
Пример: abstract void move();
- Не абстрактные методы (или конкретные методы) в абстрактных классах реализуются как обычно.
При этом наследниками абстрактного класса могут быть как другие абстрактные классы, так и классы, допускающие создание объектов, т.е. классы в которых реализованы все методы.
Если в классе присутствует хотя бы один абстрактный метод, то весь класс должен быть объявлен абстрактным.
Использование абстрактных классов и методов позволяет описать некий шаблон объекта, который должен быть реализован в других классах. В них же самих описывается лишь некое общее для всех потомков поведение.
Да, может быть конструктор (для вызовов по цепочке из наследников).
Абстрактный класс в JAVA может содержать от нуля и более абстрактных методов.
Однако, даже если абстрактный класс не содержит ни одного абстрактного метода, он все равно не может быть инстанциирован.
Ключевое слово abstract при объявлении класса говорит о том, что класс предназначен для наследования и не подразумевает его прямого использования.
В то же время не существует верхнего предела для количества абстрактных методов, которые может содержать абстрактный класс.
Вы можете иметь столько абстрактных методов, сколько вам нужно, в зависимости от того, какая структура и поведение у вас есть в вашем приложении.
Но важно помнить, что все абстрактные методы, объявленные в абстрактном классе, должны быть реализованы в любом конкретном (неабстрактном) наследнике этого абстрактного класса. Если какие-то методы не реализованы, то этот наследник также должен быть объявлен как абстрактный.
Да,
абстрактный класс в JAVA может содержать обычные методы.
Это одна из особенностей абстрактных классов.
Обычные методы в абстрактном классе - это методы, которые имеют реализацию (т.е. они не
являются абстрактными).
Эти методы могут быть вызваны напрямую из любого наследника этого абстрактного класса.
Это позволяет разработчикам предоставить общую функциональность для всех наследников,
которую можно переопределить при необходимости.
Важно помнить, что, несмотря на наличие обычных методов, абстрактные классы по-прежнему не могут быть инстанцированы. Они могут только быть расширены другими классами.
Ни одного. Невозможно создать объект абстрактного класса в JAVA.
Абстрактные классы в JAVA предназначены для того, чтобы быть унаследованными другими классами, а не для создания объектов напрямую. Если вы попытаетесь создать объект абстрактного класса, компилятор Java выдаст ошибку.
Однако, вы можете иметь ссылку на абстрактный класс, которая указывает на объект подкласса. Это полезно,
когда вы хотите использовать полиморфизм, где ссылка на родительский класс (в данном случае абстрактный
класс) может быть использована для ссылки на объект любого его насделника.
Но прямого создания объекта абстрактного класса не может быть.
Если наследник абстрактного класса не переопределяет все абстрактные методы родителя, то этот наследник также должен быть объявлен как абстрактный.
В противном случае, компилятор Java выдаст ошибку, так как любой конкретный (не абстрактный) класс, который расширяет абстрактный класс, должен предоставить реализацию для всех абстрактных методов родителя.
Объявление наследника как абстрактного означает, что он не может быть инстанциирован напрямую и должен быть расширен другим классом, который предоставит реализации для оставшихся абстрактных методов.
Это позволяет вам создавать иерархии классов, где некоторые аспекты поведения определяются на более высоком уровне, но конкретные реализации предоставляются на более низком уровне.
Можно ли создать объект интерфейса?
Какие модификаторы по умолчанию имеют поля и методы интерфейсов?
Что такое static метод интерфейса?
Что такое дефолтные методы интерфейсов?
Может ли интерфейс содержать какие-либо методы с реализацией?
Чем интерфейсы отличаются от абстрактных классов?
Ключевое слово interface используется для создания полностью абстрактных классов.
Основное предназначение интерфейса - определять каким образом мы можем использовать класс, который его реализует.
Интерфейс в JAVA может содержать следующие элементы:
Методы: Интерфейс может объявлять любое количество методов.
Все методы в интерфейсе по умолчанию являются публичными и абстрактными.
Т.е. определяются имена методов, списки аргументов и типы возвращаемых значений, но не реализуется их поведение. Все методы неявно объявляются как public.
Константы: Интерфейс может содержать переменные, которые по умолчанию являются public, static и final.
Т.е. по факту это константы.
Вложенные типы: Интерфейс может содержать вложенные интерфейсы, классы и перечисления.
Методы по умолчанию: Начиная с Java 8, интерфейсы могут содержать методы по умолчанию (default), которые предоставляют их реализацию. Методы по умолчанию помогают в расширении интерфейсов без опасения нарушения существующих классов, которые уже реализуют эти интерфейсы.
Статические методы: Также, начиная с Java 8, интерфейс может содержать статические методы.
Частные (приватные) методы: Начиная с Java 9, интерфейсы могут содержать частные (приватные) методы, которые могут быть использованы для повторного использования общего кода между методами.
Нет, напрямую создать объект интерфейса в JAVA нельзя, потому что интерфейсы не могут иметь экземпляров.
Однако вы можете объявить ссылку, которая является типом интерфейса, и эта ссылка может указывать на объект любого класса, который реализует этот интерфейс.
Кстати, можно использовать анонимные классы для создания объекта интерфейса на лету.
Объявляем переменную, пишем new ИмяИнтрефейса{и тут же реализацию методов}
Поля автоматически являются публичными public, статическими static и неизменяемыми final.
Все методы неявно объявляются как public.
Статические методы интерфейса похожи на методы по умолчанию, за исключением того, что для них отсутствует возможность переопределения в классах, реализующих интерфейс.
Статические методы в интерфейсе являются частью интерфейса без возможности использовать их для объектов класса реализации;
Методы класса java.lang.Object нельзя переопределить как статические;
Статические методы в интерфейсе используются для обеспечения вспомогательных методов, например, проверки на null, сортировки коллекций и т.д.
Если класс реализует интерфейс, он может, но не обязан, реализовать методы по-умолчанию, уже реализованные в интерфейсе. Класс наследует реализацию по умолчанию.
Дефолтные методы можно переопределить.
Если некий класс реализует несколько интерфейсов, которые имеют одинаковый метод по умолчанию, то класс должен реализовать метод с совпадающей сигнатурой самостоятельно.
Ситуация аналогична, если один интерфейс имеет метод по умолчанию, а в другом этот же метод является абстрактным - никакой реализации по умолчанию классом не наследуется.
Метод по умолчанию не может переопределить метод класса java.lang.Object.
Помогают реализовывать интерфейсы без страха нарушить работу других классов.
Позволяют избежать создания служебных классов, так как все необходимые методы могут быть представлены в самих интерфейсах.
Дают свободу классам выбрать метод, который нужно переопределить.
Одной из основных причин внедрения методов по умолчанию является возможность коллекций в JAVA 8 использовать лямбда-выражения.
Методы по умолчанию, Статические методы и Частные (приватные) методы.
Абстрактный класс связывает между собой и объединяет классы, имеющие очень близкую связь (птицы: голуби, воробьи).
В то же время, один и тот же интерфейс могут реализовать классы, у которых вообще нет ничего общего (Flyable: птицы, наркоман, самолет).
(Абстрактные классы) | (Интерфейсы) |
Сначала вызываются все статические блоки в очередности от первого статического блока корневого предка и выше по цепочке иерархии до статических блоков самого класса.
Затем вызываются нестатические блоки инициализации корневого предка, конструктор корневого предка и так далее вплоть до нестатических блоков и конструктора самого класса.
Parent static block(s) → Child static block(s) →
Grandchild static block(s) →
Parent nonstatic block(s) →
Parent constructor →
Child nonstatic block(s) → Child constructor →
Grandchild nonstatic block(s) → Grandchild constructor
Блоки инициализации представляют собой код, заключенный в фигурные скобки и размещаемый внутри класса вне объявления методов или конструкторов.
Существуют статические и нестатические блоки инициализации.
Блок инициализации выполняется перед инициализацией класса загрузчиком классов или созданием объекта класса с помощью конструктора.
Несколько блоков инициализации выполняются в порядке следования в коде класса.
Блок инициализации способен генерировать исключения, если их объявления перечислены в throws всех конструкторов класса.
Блок инициализации возможно создать и в анонимном классе.
class Dog {
private String name;
private String poroda;
private int age;
{
name = "Шарик";
poroda = "овчарка";
age = 2;
}
public Dog(String x, String y, int z){
name = x;
poroda = y;
age = z;
}
}
Статические блоки инициализация используются для выполнения кода, который должен выполняться один раз при инициализации класса загрузчиком классов, в момент предшествующий созданию объектов этого класса при помощи конструктора.
Такой блок (в отличие от нестатических, принадлежащих конкретному объекту класса) принадлежит только самому классу (объекту метакласса Class).
Если блок статический – ExceptionInInitializerError,
Если нестатический – вылетит само исключение.
Для нестатических блоков инициализации, если выбрасывание исключения прописано явным образом требуется, чтобы объявления этих исключений были перечислены в throws всех конструкторов класса. Иначе будет ошибка компиляции.
Для статического блока выбрасывание исключения в явном виде, приводит к ошибке компиляции.
В остальных случаях, взаимодействие с исключениями будет проходить так же как и в любом другом месте. Класс не будет инициализирован, если ошибка происходит в статическом блоке и объект класса не будет создан, если ошибка возникает в нестатическом блоке.
Если возникшее исключение - наследник RuntimeException:
Если возникшее исключение - наследник Error, то в обоих случаях будет выброшено java.lang.Error. Исключение: java.lang.ThreadDeath - смерть потока. В этом случае никакое исключение выброшено не будет.
Object это базовый класс для всех остальных объектов в JAVA.
Любой класс наследуется от Object и, соответственно, наследуют его методы.
Метод | Описание |
---|---|
equals() |
Служит для сравнения объектов по значению; == по ссылке public boolean equals(Object obj) |
hashCode() |
Возвращает hash код для объекта int hashCode() |
toString() |
Возвращает строковое представление объекта String toString() |
getClass() |
Возвращает класс объекта во время выполнения Class getClass() |
clone() |
Создает и возвращает копию объекта protected Object clone() |
notify() |
Возобновляет поток, ожидающий монитор void notify() |
notifyAll() |
Возобновляет все потоки, ожидающие монитор void notifyAll() |
wait() |
Остановка вызвавшего метод потока до момента пока другой поток не вызовет метод notify() или notifyAll() для этого объекта void wait() |
wait() |
Остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта void wait(long timeout) |
wait() |
Остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта void wait(long timeout, int nanos) |
finalize() |
Может вызываться сборщиком мусора в момент удаления объекта при сборке мусора. protected void finalize() |
Метод equals() - определяет отношение эквивалентности объектов.
Метод equals() - определяет отношение эквивалентности объектов.
При сравнении объектов с помощью == сравнение происходит лишь между ссылками.
При сравнении по переопределённому разработчиком equals() - по внутреннему состоянию объектов.
equals в классе Object проверяет только равенство ссылок:
public booleanequals (Object obj) { return (this == obj); }
По умолчанию каждый экземпляр равен только самому себе.
Это не всегда хорошо, поэтому для новых классов обычно переопределяют метод equals.
Рефлексивность
x.equals(x) = true
Симметричность
x.equals(y) = true
y.equals(x) = true
Транзитивность
x.equals(y) = true
y.equals(z) = true
x.equals(z) = true
Постоянство или Непротиворечивость
Результат одно и то же число пока объект не изменится
Для любых ссылок на значения х и у, если несколько раз вызвать х.equals(y), постоянно будет возвращаться значение true либо постоянно будет возвращаться значение false при условии, что никакая информация, используемая при сравнении объектов, не поменялась.
Если объекта нет - ложь
x.equals(null) = false
Для любой ненулевой ссылки на значение х выражение х.equals(null) должно возвращать false.
Обход всех значимых полей класса и проверка того, что значение поля в текущем объекте и значение того же поля в проверяемом на эквивалентность аргументе соответствуют друг другу.
Если проверки для всех полей прошли успешно, возвращается результат true, в противном случае - false.
@Override public booleanequals (Object obj) { if (this == obj)//равен сам себе return true; if (obj == null)//не равен нулю return false; if (getClass() != obj.getClass())//объекты одного класса return false; BlackBox other = (BlackBox) obj;//приведение if (varA != other.varA)//для конкретных переменных класса return false; if (varB != other.varB) return false; return true; }
Когда важны сами экземпляры, а не данные внутри них
Пример - классы Thread, RecursiveTask
Сравнение объектов вообще не предполагается
Пример - класс Pattern
Для equals всегда нужно сравнивать типы объектов через getClass.
instanceof не соблюдает правило симметрии в наследниках.
my.equals(child) == true
child.equals(my) == false // должно быть тру
Оператор instanceof нужен, чтобы проверить, был ли объект, на который ссылается
переменная X, создан на основе какого-либо класса Y.
Оператор instanceof проверяет именно происхождение объекта, а не переменной.
Метод hashCode() необходим для вычисления хэш кода объекта, переданного в качестве входного параметра.
в JAVA это целое число, в более широком смысле - битовая строка фиксированной длины,
полученная из массива произвольной длины.
Этот метод реализован таким образом, что для одного и того же входного объекта,
хэш код всегда будет одинаковым.
Следует понимать, что в JAVA множество возможных хэш кодов ограничено типом int, а множество объектов ничем не ограничено.
Из-за этого, вполне возможна ситуация, что хэш коды разных объектов могут совпасть:
public boolean equals(Object obj) { return (this == obj);}
public native int hashCode();
native означает, что реализация данного метода выполнена на другом языке (здесь на C++) и обычно возвращает адрес объекта в памяти.
Общий совет: выбирать поля, которые с большой долью вероятности будут различаться.
Для этого необходимо использовать уникальные, лучше всего примитивные поля, например такие как
id, uuid.
При этом нужно следовать правилу, если поля задействованы при вычислении hashCode(),
то они должны быть задействованы и при выполнении equals().
Классы и методы, которые используют правила этого контракта могут работать некорректно.
Так для HashMap это может привести к тому, что пара «ключ-значение», которая была в нее помещена при использовании нового экземпляра ключа не будет в ней найдена.
В HashSet при добавлении объект сначала сравнивается хэш добавляемого и существующие (быстрая проверка очень экономит время), если хэш разный – то дальше сравнивается по equals.
Множитель создает зависимость значения хэш кода от очередности обработки полей, что в итоге порождает лучшую хэш функцию.
Можно использовать если:
Если классы связаны отношением родитель-наследник, сравниваются объекты только одинаковых типов
ВАЖНО: у всех классов в иерархии должна быть аннотация
@EqualsAndHashCode.
Если у одного класса будет аннотация, а у другого явно определён equals,
то сравнения могут быть некорректны
Сравниваются все поля
Изменить список полей можно с помощью аннотаций @EqualsAndHashCode.Include и @EqualsAndHashCode.Exclude.
Или явно задать его в @EqualsAndHashCode(of = {"x"})
в JAVA, ключевое слово this используется в качестве ссылки на текущий объект, внутри которого оно используется.
Это слово может использоваться для ссылки на текущий класс экземпляр переменной, методы и конструкторы.
в JAVA вы можете вызвать метод родительского класса с помощью ключевого слова super.
Это ключевое слова используется для вызова конструктора родительского класса, а также для вызова метода родительского класса.
Вы можете использовать super для вызова любого метода, определенного в родительском классе. Если же метод не определен в родительском классе, вы получите ошибку компиляции.
Что такое не статический метод?
Что такое переопределение метода?
Можно ли переопределить статический метод?
Затенение и сокрытие метода. Чем отличаются?
Может ли статический метод быть переопределён или перегружен?
Могут ли нестатические методы перегрузить статические?
Можно ли сузить уровень доступа/тип возвращаемого значения при переопределении метода?
Статический метод в JAVA — это метод, который принадлежит классу, а не экземпляру класса (объекту). Он может быть вызван без создания объекта класса.
Статические методы объявляются с помощью ключевого слова static.
Основные характеристики статических методов:
Нестатический метод в JAVA, также известный как метод экземпляра, принадлежит конкретному объекту (экземпляру класса), а не классу в целом.
Основные характеристики нестатических методов:
Переопределение метода (Method Overriding) в JAVA - это механизм, который позволяет дочернему классу предоставить свою собственную реализацию метода, уже определенного в родительском классе.
Это важный аспект объектно-ориентированного программирования, так как он поддерживает принцип полиморфизма.
Переопределенный метод в подклассе должен иметь ту же сигнатуру, что и метод в родительском классе. Это означает, что переопределенный метод должен иметь то же имя, возвращаемый тип и параметры.
Аннотация @Override не является обязательной, но это хорошая практика использовать её при переопределении методов, так как это помогает быстрее выявить ошибки во время компиляции, если метод родительского класса не существует или имеет другую сигнатуру.
Перегрузка метода (Method Overloading) - это возможность в языке программирования Java, которая позволяет классу иметь два или более метода с одинаковым именем, но разными параметрами.
Важно помнить:
Изменение только типа возвращаемых данных не достаточно для перегрузки метода в Java.
Перегрузить метод путем изменения возвращаемого типа не допускается, если такое произойдет, будет выброшена ошибка при компиляции.
Однако, если вы измените список параметров, то сможете успешно перегрузить метод.
Нет, однако...
в JAVA статические методы не могут быть переопределены. Это связано с тем, что статические методы являются частью класса, а не экземпляра класса. Они принадлежат классу, в котором определены, и не могут быть переопределены в подклассе.
Однако, статический метод может сокрыт в подклассе.
Сокрытие метода в JAVA (Method Hiding) - это механизм, позволяющий подклассу предоставить свою собственную реализацию статического метода, уже определенного в родительском классе.
Сокрытие метода в JAVA применяется только к статическим методам. Нестатические методы поддерживают переопределение, но не сокрытие.
Затенение метода (method overriding) и сокрытие метода (method hiding) - это разные понятия в JAVA.
Затенение метода (Method Overriding): Это механизм, который позволяет подклассу предоставить реализацию метода, уже предоставленного в его суперклассе.
Этот механизм используется для достижения полиморфизма времени выполнения.
При затенении метода используется ключевое слово super.
Сокрытие метода (Method Hiding): Если суперкласс и подкласс имеют статические методы с одинаковым именем и параметрами, то метод в подклассе скрывает метод в суперклассе.
Это известно как сокрытие метода.
Важно помнить, что статические методы связаны с классом, а не с экземпляром.
Так что, хотя оба термина относятся к тому, что метод в подклассе заменяет или скрывает метод в суперклассе, они используются в разных контекстах и имеют разные последствия.
Статические методы не могут быть переопределены в точном смысле слова, но они могут скрыть родительские статические методы (затирать).
Да, могут быть перегружены. Мы можем иметь два или более статических метода с одинаковым именем, но с различиями во входных параметрах.
При переопределении метода сужать модификатор доступа нельзя, т.к. это приведет к нарушению принципа подстановки Барбары Лисков. Расширение уровня доступа возможно.
Изменять тип возвращаемого значения при переопределении метода разрешено только в сторону сужения типа (вместо родительского класса - наследника).
При изменении типа, количества, порядка следования аргументов вместо переопределения будет происходить overloading (перегрузка) метода.
Секцию throws метода можно не указывать, но стоит помнить, что она остаётся действительной, если уже определена у метода родительского класса.
Также, возможно добавлять новые исключения, являющиеся наследниками от уже объявленных или исключения RuntimeException.
Порядок следования таких элементов при переопределении значения не имеет.
Виртуальная функция - это термин, который используется в некоторых языках программирования, для обозначения метода, который может быть переопределен в производном классе.
В C++, например, виртуальные функции позволяют достичь "позднего связывания" или "динамического связывания", что является ключевой составляющей полиморфизма.
Однако в JAVA все не-статические и не-финальные методы по умолчанию являются "виртуальными" в том смысле, что они могут быть переопределены в подклассах.
Таким образом, в JAVA нет необходимости (и даже возможности) явно обозначать методы как "виртуальные" - это поведение является стандартным.
в JAVA термин effectively final
введен в JAVA 8 и относится к переменным, которые
не модифицируются после инициализации.
Другими словами, переменная "effectively final", если она не изменяется после того, как ей
впервые присваивается значение.
Это понятие используется преимущественно в контексте лямбда-выражений и анонимных классов. в JAVA 8 и более поздних версиях такие сущности могут обращаться к локальным переменным, которые являются final или "effectively final".
Технически, вам не обязательно явно объявлять переменную как final, чтобы она была "effectively final". Если Java видит, что локальная переменная не изменяется после инициализации, она считается "effectively final", и вы можете безопасно ссылаться на нее в лямбда-выражении или анонимном классе.
Подробненько тут
Record в JAVA — это нововведение, введенное в JAVA 14 в качестве превью-функции и стабилизированное в JAVA 16. Record позволяет сократить количество шаблонного кода при создании классов, которые служат просто контейнерами данных.
Record — это новый тип объявления (type of declaration) для определения неизменяемых (immutable) классов данных.
Он автоматически предоставляет реализации конструктора и методов equals(), hashCode(), toString(), а также геттеров для каждого объявленного поля (с именами полей, а не с префиксом get).
Record лучше всего подходит для небольших и неизменяемых классов данных. Они не предназначены для больших классов с некоторой сложной логикой или состоянием.
Помимо этого, Record не может наследоваться от другого класса (кроме java.lang.Record) и не может быть суперклассом.
Varargs (Variable-Length Arguments)
- это возможность в JAVA, которая позволяет методу принимать нуль или
более аргументов одного типа.
Это очень удобно, когда вы не знаете, сколько аргументов нужно передать методу.
Вы можете определить varargs в методе, указав тип аргумента, за которым следуют три точки (...).
Например:
public voidprintNumbers (int... numbers) { for (int number : numbers) { System.out.println(number); } }
Теперь вы можете вызвать этот метод с любым количеством аргументов типа int (включая ноль аргументов):
printNumbers(); // No arguments printNumbers(1); // One argument printNumbers(1, 2, 3); // Three arguments
Varargs очень полезны, когда вы создаете методы, которые требуют произвольного числа аргументов.
Однако стоит
быть осторожным при использовании varargs вместе с другими аргументами
, так как порядок аргументов становится важным.
Varargs должен быть последним в списке аргументов метода.
Неоднозначность при работе с varargs в JAVA может возникнуть в следующих случаях:
Перегрузка методов с varargs и без.
Если у вас есть перегруженные методы, один из которых принимает varargs, а другой
- фиксированное количество аргументов, компилятор может не определить, какой метод
вызвать.
Например, если у вас есть методы foo(int a, int b) и foo(int... a), вызов foo(1, 2) может быть неоднозначным.
Перегрузка методов с разными типами varargs.
Если у вас есть два метода, оба с varargs, но с разными типами, и вы пытаетесь вызвать метод
с
аргументами, которые могут быть приведены к обоим типам, это может привести к неоднозначности.
Например, есть методы foo(Integer... a) и foo(String... a),, вызов foo(null) может вызвать неоднозначность.
Во всех этих случаях, чтобы избежать неоднозначности, нужно более ясно указать, какой метод вы хотите вызвать, возможно, явно приведя типы аргументов или явно создав массив для varargs.