Перейти к содержимому

Как переопределить метод в java

  • автор:

Переопределение методов

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

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

В следующем примере в классе M определен метод print() . В его наследнике классе N тоже определен метод print() с такой же сигнатурой, но другим поведением. Это и называется переопределением методов:

public class M < public int i; public int j; public M(int i, int j) < this.i = i; this.j = j; >public void print() < System.out.println("Метод M i = " + i + " j language-java">public class N extends M < public int k; public N(int i, int j, int k) < super(i, j); this.k = k; >public void print() < System.out.println("Метод N k language-java">public class OverrideDemo < public static void main(String[] args) < M obj1 = new M(7, 8); obj1.print(); N obj2 = new N(4, 5, 6); obj2.print(); M obj3 = new N(1, 2, 3); obj3.print(); >>
Метод M i = 7 j = 8 Метод N k = 6 Метод N k = 3

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

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

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

Создадим класс Figure , описывающий какую-то абстрактную фигуру и классы наследники Triangle и Rectangle . Класс Figure содержит метод calculateArea() , подсчитывающий площадь фигуры. У каждой фигуры своя формула для подсчета площади, поэтому в классах Triangle и Rectangle метод calculateArea() переопределяется соответствующим образом:

public class Figure < double dimension1; double dimension2; public Figure(double dimension1, double dimension2) < this.dimension1 = dimension1; this.dimension2 = dimension2; >public double calculateArea() < System.out.println("Площадь фигуры не определена."); return 0; >>
public class Rectangle extends Figure < public Rectangle(double dimension1, double dimension2) < super(dimension1, dimension2); >public double calculateArea() < System.out.println("B области четырехугольника."); return dimension1 * dimension2; >>
public class Triangle extends Figure < public Triangle(double dimension1, double dimension2) < super(dimension1, dimension2); >public double calculateArea() < System.out.println("B области треугольника."); return dimension1 * dimension2 / 2; >>

Создадим массив типа Figure , который будет содержать объекты типа Figure , Triangle и Rectangle . Подсчитаем площадь для каждого элемента перебирая элементы массива и вызывая метод calculateArea() для каждого элемента. Нам все равно какого типа объект - у каждого есть вызываемый метод calculateArea() . JVM с помощью динамической диспетчеризации выбирает нужный вариант метода, основываясь на реальном типе объекта:

public class FindAreas < public static void main(String[] args) < Figure[] figures = new Figure[3]; figures[0] = new Figure(10, 10); figures[1] = new Rectangle(10, 10); figures[2] = new Triangle(10, 10); for (Figure figure : figures) < double area = figure.calculateArea(); System.out.println(area); >> >

Результат выполнения кода:

Площадь фигуры не определена. 0.0 B области четырехугольника. 100.0 B области треугольника. 50.0

2. Методы подставки

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

Например, класс S наследует класс R и переопределяет метод getInstance() . При переопределении возвращаемый тип метода может или остаться таким же - Box6 , или быть изменен на любого наследника класса Box6 - HeavyBox , ColorBox или Shipment :

public class R < Box6 getInstance() < return new Box6(); >>
public class S extends R < HeavyBox getInstance() < return new HeavyBox(); >> 

3. Переопределение и статические методы

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

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

Создадим в супер классе и наследнике статические методы с одинаковой сигнатурой:

public class Base < public static void go() < System.out.println("метод из Base"); >>
public class Sub extends Base < public static void go() < System.out.println("метод из Sub"); >>

Попробуем вызвать статический метод используя переменную типа Base , которая указывает на объект типа Sub . При вызове статического метода JVM найдет тип переменной и вызовет метод того же класса:

public class Runner < public static void main(String[] args) < Base ob = new Sub(); ob.go(); Sub.go(); >>
метод из Base метод из Sub

4. Переопределение методов в классах наследниках

Методы объявленные как private никто, кроме самого класса не видит. Поэтому их наличие/отсутствие никак не отражается на классах наследниках. Они с легкостью могут объявлять методы с такой же сигнатурой и любыми модификаторами. Но это плохой тон! Также класс наследник может расширить видимость protected метода до public . Сузить видимость класс наследник не может.

5. Аннотация @Override

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

public class S extends R < @Override HeavyBox getInstance() < return new HeavyBox(); >>
  • Процедурное и объектно-ориентированное программирование
  • Принципы ООП
  • Классы и объекты
  • Конструктор
  • Ключевое слово this
  • Перегрузка
  • Стек и куча
  • Передача объектов в методы
  • Java varargs
  • Рекурсия
  • Сборщик мусора и метод finalize
  • Наследование
  • Ключевое слово super
  • Модификаторы доступа
  • Геттеры и сеттеры
  • Абстрактные классы и методы
  • Ключевое слово final
  • Задания

Как переопределить метод в java

В Java метод можно переопределить в классе-потомке, при условии, что метод в классе-родителе был объявлен с модификатором доступа public или protected , и совпадает по имени и списку параметров.

Для переопределения метода в Java необходимо в классе-потомке объявить метод с таким же именем, списком параметров и типом возвращаемого значения, как у метода в классе-родителе, и пометить его аннотацией @Override . В теле метода необходимо описать новую реализацию метода.

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

public class Animal  public void makeSound()  System.out.println("The animal makes a sound"); > > public class Cat extends Animal  @Override public void makeSound()  System.out.println("The cat meows"); > > 

В данном примере метод makeSound() переопределен в классе Cat , который является потомком класса Animal . При вызове метода makeSound() на объекте типа Cat будет выполнена реализация метода из класса Cat , а не из класса Animal .

24. Java – Переопределение (overriding)

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

Так что такое в Java overriding или override – это переопределение.

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

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

Пример 1

class Animal < public void move() < System.out.println("Животные могут двигаться"); >> class Dog extends Animal < public void move() < System.out.println("Собаки могут ходить и бегать"); >> public class TestDog < public static void main(String args[]) < Animal a = new Animal(); // Animal - ссылка и объект Animal b = new Dog(); // Animal - ссылка, но Dog - объект a.move(); // Запускает метод в классе Animal b.move(); // Запускает метод в классе Dog >> 

После запуска программы будет выдан такой результат:

Животные могут двигаться Собаки могут ходить и бегать 

В вышеприведённом примере вы можете заметить, что b хоть и является типом Animal, оно запускает метод move в классе Dog. Причина тому: во время компиляции проходит проверка ссылочного типа. Однако, во время выполнения, JVM определяет тип объекта и запускает метод, который принадлежит этому конкретному объекту.

Следовательно, по примеру выше, программа запустится правильно, так как класс Animal имеет метод move. Затем, во время выполнения, он запускает метод, принадлежащий этому объекту.

Рассмотрите следующий пример:

Пример 2

class Animal < public void move() < System.out.println("Животные могут двигаться"); >> class Dog extends Animal < public void move() < System.out.println("Собаки могут ходить и бегать"); >public void bark() < System.out.println("Собаки могут лаять"); >> public class TestDog < public static void main(String args[]) < Animal a = new Animal(); // Animal - ссылка и объект Animal b = new Dog(); // Animal - ссылка, но Dog - объект a.move(); // Запускает метод в классе Animal b.move(); // Запускает метод в классе Dog b.bark(); >> 

После запуска программы будет выдан такой результат:

TestDog.java:26: error: cannot find symbol b.bark(); ^ symbol: method bark() location: variable b of type Animal 1 error 

Программа выдаст ошибку во время компиляции, так как ссылочный тип b у Animal не имеет метода под именем bark.

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

  • Список аргументов должен быть точно таким же, как и для переопределённого метода.
  • Возвращаемый тип должен быть таким же или подтипом возвращаемого типа, объявленного в исходном переопределенном методе в суперклассе.
  • Уровень доступа не может быть более ограниченным, чем уровень доступа переопределённого метода. Например, если метод суперкласса объявлен public, то переопределяемый метод в подклассе не может быть private или protected.
  • Методы экземпляров могут быть переопределены только если они наследованы подклассом.
  • Методы, которые объявлены как final, не могут быть переопределены.
  • Статические методы, которые объявлены как static, не могут быть переопределены, но могут быть повторно объявлены.
  • Если метод нельзя наследовать, то его нельзя переопределить.
  • Подкласс внутри того же пакета, что и суперкласс экземпляра, может переопределять любой метод суперкласса, который не объявлен как private или final.
  • Подкласс в другом пакете может переопределять только не final методы, объявленные как public или protected.
  • Переопределяемый метод может выдавать любые непроверенные исключения вне зависимости от того, переопределяет ли переопределённый метод какие-либо непроверенные исключения или нет. Однако, переопределяемый метод не должен генерировать проверенные исключения, которые являются новыми или более широкими, чем те, которые объявлены переопределённым методом. Переопределенный метод может генерировать более узкие или меньшие исключения, чем переопределенный метод.
  • Конструкторы нельзя переопределить.

Использование ключевого слова super

Вызывая версию суперкласса переопределённого метода, используется ключевое слово super.

Пример

class Animal < public void move() < System.out.println("Животные могут двигаться"); >> class Dog extends Animal < public void move() < super.move(); // Вызывает метод суперкласса System.out.println("Собаки могут ходить и бегать"); >> public class TestDog < public static void main(String args[]) < Animal b = new Dog(); // Animal - ссылка, но Dog - объект b.move(); // Запуск метода в классе Dog >> 

После запуска программы будет выдан такой результат:

Животные могут двигаться Собаки могут ходить и бегать 

Оглавление

  • 1. Java – Самоучитель для начинающих
  • 2. Java – Обзор языка
  • 3. Java – Установка и настройка
  • 4. Java – Синтаксис
  • 5. Java – Классы и объекты
  • 6. Java – Конструкторы
  • 7. Java – Типы данных и литералы
  • 8. Java – Типы переменных
  • 9. Java – Модификаторы
  • 10. Java – Операторы
  • 11. Java – Циклы и операторы цикла
  • 11.1. Java – Цикл while
  • 11.2. Java – Цикл for
  • 11.3. Java – Улучшенный цикл for
  • 11.4. Java – Цикл do..while
  • 11.5. Java – Оператор break
  • 11.6. Java – Оператор continue
  • 12. Java – Операторы принятия решений
  • 12.1. Java – Оператор if
  • 12.2. Java – Оператор if..else
  • 12.3. Java – Вложенный оператор if
  • 12.4. Java – Оператор switch..case
  • 12.5. Java – Условный оператор (? 🙂
  • 13. Java – Числа
  • 13.1. Java – Методы byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()
  • 13.2. Java – Метод compareTo()
  • 13.3. Java – Метод equals()
  • 13.4. Java – Метод valueOf()
  • 13.5. Java – Метод toString()
  • 13.6. Java – Метод parseInt()
  • 13.7. Java – Метод Math.abs()
  • 13.8. Java – Метод Math.ceil()
  • 13.9. Java – Метод Math.floor()
  • 13.10. Java – Метод Math.rint()
  • 13.11. Java – Метод Math.round()
  • 13.12. Java – Метод Math.min()
  • 13.13. Java – Метод Math.max()
  • 13.14. Java – Метод Math.exp()
  • 13.15. Java – Метод Math.log()
  • 13.16. Java – Метод Math.pow()
  • 13.17. Java – Метод Math.sqrt()
  • 13.18. Java – Метод Math.sin()
  • 13.19. Java – Метод Math.cos()
  • 13.20. Java – Метод Math.tan()
  • 13.21. Java – Метод Math.asin()
  • 13.22. Java – Метод Math.acos()
  • 13.23. Java – Метод Math.atan()
  • 13.24. Java – Метод Math.atan2()
  • 13.25. Java – Метод Math.toDegrees()
  • 13.26. Java – Метод Math.toRadians()
  • 13.27. Java – Метод Math.random()
  • 14. Java – Символы
  • 14.1. Java – Метод Character.isLetter()
  • 14.2. Java – Метод Character.isDigit()
  • 14.3. Java – Метод Character.isWhitespace()
  • 14.4. Java – Метод Character.isUpperCase()
  • 14.5. Java – Метод Character.isLowerCase()
  • 14.6. Java – Метод Character.toUpperCase()
  • 14.7. Java – Метод Character.toLowerCase()
  • 14.8. Java – Метод Character.toString()
  • 15. Java – Строки
  • 15.1. Java – Метод charAt()
  • 15.2. Java – Метод compareTo()
  • 15.3. Java – Метод compareToIgnoreCase()
  • 15.4. Java – Метод concat()
  • 15.5. Java – Метод contentEquals()
  • 15.6. Java – Метод copyValueOf()
  • 15.7. Java – Метод endsWith()
  • 15.8. Java – Метод equals()
  • 15.9. Java – Метод equalsIgnoreCase()
  • 15.10. Java – Метод getBytes()
  • 15.11. Java – Метод getChars()
  • 15.12. Java – Метод hashCode()
  • 15.13. Java – Метод indexOf()
  • 15.14. Java – Метод intern()
  • 15.15. Java – Метод lastIndexOf()
  • 15.16. Java – Метод length()
  • 15.17. Java – Метод matches()
  • 15.18. Java – Метод regionMatches()
  • 15.19. Java – Метод replace()
  • 15.20. Java – Метод replaceAll()
  • 15.21. Java – Метод replaceFirst()
  • 15.22. Java – Метод split()
  • 15.23. Java – Метод startsWith()
  • 15.24. Java – Метод subSequence()
  • 15.25. Java – Метод substring()
  • 15.26. Java – Метод toCharArray()
  • 15.27. Java – Метод toLowerCase()
  • 15.28. Java – Метод toString()
  • 15.29. Java – Метод toUpperCase()
  • 15.30. Java – Метод trim()
  • 15.31. Java – Метод valueOf()
  • 15.32. Java – Классы StringBuilder и StringBuffer
  • 15.32.1. Java – Метод append()
  • 15.32.2. Java – Метод reverse()
  • 15.32.3. Java – Метод delete()
  • 15.32.4. Java – Метод insert()
  • 15.32.5. Java – Метод replace()
  • 16. Java – Массивы
  • 17. Java – Дата и время
  • 18. Java – Регулярные выражения
  • 19. Java – Методы
  • 20. Java – Потоки ввода/вывода, файлы и каталоги
  • 20.1. Java – Класс ByteArrayInputStream
  • 20.2. Java – Класс DataInputStream
  • 20.3. Java – Класс ByteArrayOutputStream
  • 20.4. Java – Класс DataOutputStream
  • 20.5. Java – Класс File
  • 20.6. Java – Класс FileReader
  • 20.7. Java – Класс FileWriter
  • 21. Java – Исключения
  • 21.1. Java – Встроенные исключения
  • 22. Java – Вложенные и внутренние классы
  • 23. Java – Наследование
  • 24. Java – Переопределение
  • 25. Java – Полиморфизм
  • 26. Java – Абстракция
  • 27. Java – Инкапсуляция
  • 28. Java – Интерфейсы
  • 29. Java – Пакеты
  • 30. Java – Структуры данных
  • 30.1. Java – Интерфейс Enumeration
  • 30.2. Java – Класс BitSet
  • 30.3. Java – Класс Vector
  • 30.4. Java – Класс Stack
  • 30.5. Java – Класс Dictionary
  • 30.6. Java – Класс Hashtable
  • 30.7. Java – Класс Properties
  • 31. Java – Коллекции
  • 31.1. Java – Интерфейс Collection
  • 31.2. Java – Интерфейс List
  • 31.3. Java – Интерфейс Set
  • 31.4. Java – Интерфейс SortedSet
  • 31.5. Java – Интерфейс Map
  • 31.6. Java – Интерфейс Map.Entry
  • 31.7. Java – Интерфейс SortedMap
  • 31.8. Java – Класс LinkedList
  • 31.9. Java – Класс ArrayList
  • 31.10. Java – Класс HashSet
  • 31.11. Java – Класс LinkedHashSet
  • 31.12. Java – Класс TreeSet
  • 31.13. Java – Класс HashMap
  • 31.14. Java – Класс TreeMap
  • 31.15. Java – Класс WeakHashMap
  • 31.16. Java – Класс LinkedHashMap
  • 31.17. Java – Класс IdentityHashMap
  • 31.18. Java – Алгоритмы Collection
  • 31.19. Java – Iterator и ListIterator
  • 31.20. Java – Comparator
  • 32. Java – Дженерики
  • 33. Java – Сериализация
  • 34. Java – Сеть
  • 34.1. Java – Обработка URL
  • 35. Java – Отправка Email
  • 36. Java – Многопоточность
  • 36.1. Java – Синхронизация потоков
  • 36.2. Java – Межпоточная связь
  • 36.3. Java – Взаимная блокировка потоков
  • 36.4. Java – Управление потоками
  • 37. Java – Основы работы с апплетами
  • 38. Java – Javadoc

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

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

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

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

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

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

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

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

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

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

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

Использование Override

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

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

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

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

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

package com.me.overriding; class Parent_params < void method(String a, String b, int v, float d) < System.out.println("parent"); >void method2(String a, String b, int v) < System.out.println("parent"); >void method3(String a, int v) < System.out.println("parent"); >> class Child_Params extends Parent_params < //Если мы хотим переопределить дочерний класс, //вам нужно иметь такое же количество параметров, что и родительский //НЕПРАВИЛЬНО. /*@Override void method(String a)< System.out.println("child"); >*/ //Порядок параметров должен также совпадать с родительским //НЕПРАВИЛЬНО /*@Override void method(String a,float d,int a,String b)< System.out.println("parent"); >*/ //Override @Override void method(String a, String b, int v, float d) < System.out.println("child"); >//Перегрузка //Мы можем определить метод таким образом void method(String a, String b, int v) < System.out.println("child"); >void method2(String a, int b, String v) < System.out.println("child"); >void method3(int v, String a) < System.out.println("child"); >> public class Override_Params < public static void main(String[] args) < String temp = "Monday"; Child_Params child_Params = new Child_Params(); /*Parent_params params=new Child_Params(); child_Params=(Child_Params) params; child_Params.method(temp,temp,2);*/ Parent_params params2 = new Parent_params(); child_Params = (Child_Params) params2; child_Params.method(temp, temp, 2); /*up vote 3 down vote accepted Создав объект, вы не можете изменить его тип. Вот почему вы не можете привести тип Animal к типу Dog. Однако, если вы создаете объект подкласса, вы можете сохранить ссылку на него в переменной типа суперкласса, и позже вы можете применить его к типу подкласса. Это будет работать : Animal a = new Dog (); Dog d = (Dog) a;*/ >>

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

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

  • Если R1 void, то R2 является void.
  • Если R1 является примитивным типом, то R2 идентичен R1.
  • Если R1 является ссылочным типом, то: R1 является либо подтипом R2, либо R1 может быть преобразован в подтип R2 путем unchecked преобразования или
  • R1 = | R2 |
package com.me.overriding; class Parent1 < public void method(String string) < System.out.println("Parent :" + string); >public void method2(String string) < System.out.println("Parent :" + string); >> class Child1 extends Parent1 < //Тип возврата несовместим с Parent1.method (String) @Override public int method(String string) < System.out.println("Child :" + string); >> public class OverrideAllMethods < public static void main(String[] args) < Child1 child1 = new Child1(); child1.method("Me"); >>

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

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

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

package com.me.overriding; class ParentCustomClass < public Object m1() < System.out.println(" parent m1()"); return null; >public ParentCustomClass m2() < System.out.println(" parent m2()"); return null; >> class ChildtCustomClass extends ParentCustomClass < @Override public String m1() < System.out.println("child m1()"); return null; >@Override public ChildtCustomClass m2() < System.out.println(" child m2()"); return null; >> public class CoVarientTypes < public static void main(String[] args) < ParentCustomClass class1 = new ChildtCustomClass(); class1.m1(); class1.m2(); /*Объявление метода d1 с типом возврата R1 является тип-возврата-заменяемым для другого метода d2 с типом возврата R2, тогда и только тогда, когда выполняются следующие условия: Если R1 является примитивным типом, то R2 идентичен R1. Если R1 недействителен, то R2 является недействительным. Если R1 является примитивным типом, то R2 идентичен R1. Если R1 является ссылочным типом, тогда: R1 является либо подтипом R2, либо R1 может быть преобразован в подтип R2 путем беспрепятственного преобразования или R1 = |R2|*/ >>

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

package com.me.overriding; class ParentStatic < public static void method(String string) < System.out.println("Parent :" + string); >public void method2(String string) < System.out.println("Parent :" + string); >> class ChildStatic extends ParentStatic < public static void method(String string) < System.out.println("Child :" + string); >> public class StaticMethodOverriding < public static void main(String[] args) < /*1)Для методов класса (или статических методов) вызывается метод в соответствии с типом ссылки, которое означает, что вызов метода определяется во время компиляции 2) Для методов экземпляра (или нестатических методов), метод вызывается в соответствии с типом передаваемого объекта, а не по типу ссылки, что означает, что вызовы метода разрешаются во время выполнения. */ ChildStatic.method("Me"); ParentStatic parentStatic = new ChildStatic(); parentStatic.method("Me"); >>

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

package com.me.overriding; class Dad < private static final String me = "dad"; protected String getMe() < return me; >public void printMe() < System.out.println(getMe()); >> class Son extends Dad < private static final String me = "son"; @Override protected String getMe() < return me; >> class StaticVariableOverriding < public static void main(String[] args) < Dad dad = new Son(); dad.printMe(); >>

Final и private методы

package com.me.overriding; class Parent_2 < public final void m1() < System.out.println("m1()"); >private void m2() < System.out.println("m2() parent"); >> // Невозможно переопределить конечный метод из Parent_2 class Child_2 extends Parent_2 < public fianl void m1() < System.out.println("m1()"); >private void m2() < System.out.println("m2() of child"); >> public class FinalandprivateOverriden < public static void main(String[] args) < Parent_2 child_2 = new Child_2(); child_2.m1(); // Метод m2 () из типа Parent_2 не отображается child_2.m2(); >>hild_2.m2(); > >

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

package com.me.overriding; class Parent_Access < protected void method(String a, String b, int v, float d) < System.out.println("parent"); >> class Child_Access extends Parent_Access < //Уровни доступа не могут быть ограничительными /*private void method(String a,String b,int v,float d)< System.out.println("parent"); >*/ public void method(String a, String b, int v, float d) < System.out.println("parent"); >> public class Override_AccessLevels < public static void main(String[] args) < >>

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

package com.me.overriding; class SuperParent < public void m1() < System.out.println(" super m1()"); >protected void m2() < System.out.println(" super m2()"); >private void m3() < System.out.println(" super m3()"); >> class SuperChild extends SuperParent < public void m1() < super.m1(); super.m2(); System.out.println("m1()"); >protected void m2() < System.out.println("m2()"); >private void m3() < System.out.println(" m3()"); >> public class OverridingWithSuper < public static void main(String[] args) < SuperParent parent = new SuperChild(); parent.m1(); parent.m2(); >>

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

package com.me.overriding; interface Interface < public void m1(); >/*Если абстрактный класс реализует вышеуказанный интерфейс, то он не требует, чтобы подкласс определял метод move () как показано в следующем классе AbstractDog:*/ abstract class AbstractClass implements Interface < public abstract void m2(); public void m3() < System.out.println("m3()"); >> /*//Но если конкретный (не абстрактный) класс является подклассом класса AbstractDog или интерфейса Animal, тогда он должен переопределить все унаследованные абстрактные методы, как показано ниже:*/ class ConcreteClass extends AbstractClass < @Override public void m1() < // TODO Автоматически сгенерированный метод заглушки System.out.println("m1()"); >@Override public void m2() < // TODO Автоматически сгенерированный метод заглушки System.out.println("m2()"); >@Override public void m3() < // TODO Автоматически сгенерированный метод заглушки System.out.println("m3()"); >> public class OverridingWithAbstraction < public static void main(String[] args) < ConcreteClass class1 = new ConcreteClass(); class1.m1(); class1.m2(); class1.m3(); >>

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

package com.me.overriding; import java.io.IOException; import java.nio.file.DirectoryIteratorException; class ExceptionParent < public void m1() throws IOException < System.out.println("m1()"); >> // Исключение несовместимо с предложением throws в ExceptionParent.m1 () // Это должно быть выборочное или суженное или непроверенное исключение // CE /* класс ExceptionChild расширяет ExceptionParent < public void m1 () throws Exception < System.out.println ( "m1 ()"); >*/ // CE // IllegalArgumentException не проверяется /* класс ExceptionChild расширяет ExceptionParent < public void m1 () throws Exception, IllegalArgumentException < System.out.println ( "m1 ()"); >*/ // OK bccz неконтролируемого исключения /* класс ExceptionChild расширяет ExceptionParent < public void m1 () throws IllegalArgumentException < System.out.println ( "m1 ()"); >*/ /*// CE bcz of Checked класс ExceptionChild расширяет ExceptionParent < public void m1 () throws IOException, InterruptedException < System.out.println ( "m1 ()"); >*/ class ExceptionChild extends ExceptionParent < public void m1() throws IOException < System.out.println("m1()"); >> public class OverridingExceptions < public static void main(String[] args) throws IOException < ExceptionParent exceptionParent = new ExceptionChild(); exceptionParent.m1(); >>

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

package com.me.overriding; /* Java-программа, чтобы продемонстрировать, можем ли мы переопределить частный метод внешнего класса внутри его внутреннего класса */ public class OverrideprivateInnerclass < private String msg = "GeeksforGeeks"; private void fun() < System.out.println("Outer fun()"); >class Inner extends OverrideprivateInnerclass < private void fun() < System.out.println("Accessing Private Member of Outer: " + msg); >> public static void main(String args[]) < // Чтобы создать экземпляр класса Inner, нам нужен Outer // экземпляр класса. Итак, сначала создайте экземпляр класса Outer, а затем // внутренний экземпляр класса. OverrideprivateInnerclass o = new OverrideprivateInnerclass(); Inner i = o.new Inner(); // Это вызовет функцию Inner, цель этого вызова - // показать, что к приватным членам Outer можно получить доступ в Inner. i.fun(); // o.fun() calls Outer's fun (No run-time polymorphism). o = i; o.fun(); >>

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

package com.me.overriding; class ParentStatic_1 < public void method(String string) < System.out.println("Parent :" + string); >public void method2(String string) < System.out.println("Parent :" + string); >> class ChildStatic_1 extends ParentStatic_1 < public static void method(String string, int b) < System.out.println("Child :" + string); >public static void method2(String string, int b, float c) < System.out.println("Child :" + string); >> public class OverrideAndOverloadMethods < public static void main(String[] args) < //В подклассе (или производном классе) мы можем перегрузить методы, //унаследованные от суперкласса. Такие перегруженные методы не скрывают //и не переопределяют методы суперкласса - это новые методы, //уникальные для подкласса. ParentStatic_1 parentStatic = new ChildStatic_1(); parentStatic.method("Me"); >>

Многоуровневое переопределение

package com.me.overriding; class ParentStatic_2 < public void method(String string) < System.out.println("Parent :" + string); >public void method2(String string) < System.out.println("Parent :" + string); >> class ChildStatic_2 extends ParentStatic_2 < public void method(String string) < System.out.println("Child -1 :" + string); >> class ChildStatic_3 extends ChildStatic_2 < public void method(String string) < System.out.println("Child -2 :" + string); >> class ChildStatic_4 extends ChildStatic_3 < public void method(String string) < System.out.println("Child -3 :" + string); >> public class MultilevelOverriding < public static void main(String[] args) < //Нам не нужно переписывать все методы, которые есть в суперклассе. ParentStatic_2 parentStatic_2 = new ChildStatic_3(); parentStatic_2.method("hey. "); >>

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

package com.me.overriding; class ParentStatic2 < public static void method(String string) < System.out.println("Parent :" + string); >public void method2(String string) < System.out.println("Parent :" + string); >> class ChildStatic2 extends ParentStatic < //Этот статический метод не может скрыть метод экземпляра из ParentStatic public void method(String string) < System.out.println("Child :" + string); >//Этот статический метод не может скрыть метод экземпляра из ParentStatic public static void method2(String string) < System.out.println("Child :" + string); >> public class InstanceVsStaticOverriding < public static void main(String[] args) < //Метод экземпляра не может переопределить статический метод, //и статический метод не может скрыть метод экземпляра. ParentStatic2 parentStatic = new ChildStatic2(); parentStatic.method("Me"); >>

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

package com.me.overriding; class B < int a=10; public void print() < System.out.println("inside B super class"); >> class C extends B < int a=20; public void print() < System.out.println("inside C sub class"); >> public class InstanceVariableOverriding < public static void main(String[] args) < B b=new C(); b.print();//it will print inside c sub class System.out.println(b.a);//it will print super class variable value=10 /* Почему переменная экземпляра суперкласса не переопределяется в методе подкласса, см. мой код ниже . Потому что переменные экземпляра не могут быть переопределены в Java. В Java могут быть переопределены только методы. Когда вы объявляете поле с тем же именем, что и существующее поле в суперклассе, новое поле скрывает существующее поле. Существующее поле из суперкласса все еще присутствует в подклассе и может даже использоваться . с учетом обычных правил доступа к Java. */ >>

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

package com.me.overriding; class One < public One() < // Конструктор суперкласса >One(int a) < // Перегрузка конструктора суперкласса >> class Two extends One < /* < //One() < // это метод не конструктор // потому что имя не должно совпадать с именем класса >*/ Two() < // конструктор подкласса >Two(int b) < // перегрузка конструктора подкласса >> public class ConstructorOverriding < /*Это невозможно. Переопределение конструктора невозможно на Java. Это связано с тем, что конструктор выглядит как метод, но с именем класса и без возвращаемого значения. Переопределение означает что то, что мы объявили в классе Super, именно это мы и должны объявить в Sub-классе. Имя суперкласса и имена подкласса различны. Если вы попытаетесь написать Super Class Constructor в Sub-классе, тогда Sub-класс будет рассматривать это как метод не конструктор, потому что имя не должно совпадать с именем Sub-класса. И это даст ошибку компиляции, что методы не имеют возвращаемого значения. Поэтому мы должны объявить как void, только тогда она будет компилироваться. */ >

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

package com.me.overriding; class Superclass < public Superclass(int x) < System.out.println("000000"); >public Superclass() < System.out.println(" ty"); >public Superclass(String y) <> > class Subclass extends Superclass < public Subclass() < // super (5); // цепочка к Superclass(int) конструктору >> public class ConstructorWithSuper < public static void main(String[] args) < new Subclass(); >>

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

package com.me.overridingtest; import com.me.overriding.PackageParent; public class Child extends PackageParent < @Override public void m1() < System.out.println("m1()"); >@Override protected void m2() < System.out.println("m2()"); >//Методы default разрешены только в интерфейсе /*default void m3()< System.out.println("m3()"); >*/ //Подкласс в другом пакете может переопределять только не final //методы объявленные как public или protected. @Override private void m4() < System.out.println("m1()"); >> package com.me.overriding; import com.me.overridingtest.Parent; public class OtherPackageOverride < public static void main(String[] args) < Parent parent = new com.me.overridingtest.Child(); parent.m1(); parent.m2(); >> package com.me.overriding; public class PackageParent < public void m1() < System.out.println("m1()"); >protected void m2() < System.out.println("m2()"); >//Методы default разрешены только в интерфейсе /*default void m3()< System.out.println("m3()"); >*/ private void m4() < System.out.println("m1()"); >>

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

// Правила ребенок-родитель с отношением IS-A: package com.me.overriding; class Parent < public void method(String string) < System.out.println("Parent :" + string); >public void method2(String string) < System.out.println("Parent :" + string); >> class Child extends Parent < @Override public void method(String string) < System.out.println("Child :" + string); >> public class ChildParenRule < public static void main(String[] args) < // Все хорошо, он распечатает // Parent: Me // Parent parent=new Parent(); // parent.method("Me"); // Если мы прокомментируем метод в Parent и удалим переопределение в дочернем // Он бросает CE // если мы отбросим его к ребенку, получим RE // Исключение в потоке "main" // java.lang.ClassCastException: com.me.overriding.Parent // не может быть добавлен в com.me.overriding.Child // at com.me.overriding.ChildParenRule.main (ChildParenRule.java:19) // Parent parent=new Child(); // parent.method("Me"); // Вызов дочернего метода Метод, если не найдены вызовы // Метод родительского класса // Child child = new Child (); // child.method("Me "); // Хотя тип ссылки - это переопределение родительского элемента, // происходит на RE // Он будет принимать в качестве дочернего объекта и вызывает метод child // если нет, он будет искать метод родительского класса // Parent parent=new Child(); // parent.method("Me"); // CE как несоответствие типа: невозможно преобразовать из родителя в ребенка // Мы не можем преобразовать родительский элемент в дочерний класс // Исключение в потоке "main" java.lang.Error: // нерешенные проблемы компиляции: // Ошибка синтаксиса, вставьте «VariableDeclarators» для завершения // LocalVariableDeclaration // Ошибка синтаксиса, вставить «;» для завершения // LocalVariableDeclarationStatement // at com.me.overriding.ChildParenRule.main (ChildParenRule.java:53) // Child child = (Child) new Parent (); // child.method("Me "); // /* 6 down vote Родительский класс не должен знать о дочерних классах. Parent parent=new Parent(); ((Child)parent).method("Me");*/ >>

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

package com.me.overriding; // Методы экземпляров предпочтительнее, чем методы интерфейса по умолчанию. // Рассмотрим следующие классы и интерфейсы: class Horse1 < public String identifyMyself() < return "I am a horse."; >> interface Flyer < default public String identifyMyself() < return "I am able to fly."; >> interface Mythical < default public String identifyMyself() < return "I am a mythical creature."; >> public class Pegasus extends Horse1 implements Flyer, Mythical < public static void main(String. args) < Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); >> // Метод Pegasus.identifyMyself возвращает строку I am a horse.

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *