Что такое перегрузка метода в java
Перейти к содержимому

Что такое перегрузка метода в java

  • автор:

Defining Methods

The only required elements of a method declaration are the method's return type, name, a pair of parentheses, () , and a body between braces, <> .

More generally, method declarations have six components, in order:

  1. Modifiers—such as public , private , and others you will learn about later.
  2. The return type—the data type of the value returned by the method, or void if the method does not return a value.
  3. The method name—the rules for field names apply to method names as well, but the convention is a little different.
  4. The parameter list in parenthesis—a comma-delimited list of input parameters, preceded by their data types, enclosed by parentheses, () . If there are no parameters, you must use empty parentheses.
  5. An exception list—to be discussed later.
  6. The method body, enclosed between braces—the method's code, including the declaration of local variables, goes here.

Modifiers, return types, and parameters will be discussed later in this lesson. Exceptions are discussed in a later lesson.

The signature of the method declared above is:

Naming a Method

Although a method name can be any legal identifier, code conventions restrict method names. By convention, method names should be a verb in lowercase or a multi-word name that begins with a verb in lowercase, followed by adjectives, nouns, etc. In multi-word names, the first letter of each of the second and following words should be capitalized. Here are some examples:

Typically, a method has a unique name within its class. However, a method might have the same name as other methods due to method overloading.

Overloading Methods

The Java programming language supports overloading methods, and Java can distinguish between methods with different method signatures. This means that methods within a class can have the same name if they have different parameter lists (there are some qualifications to this that will be discussed in the lesson titled "Interfaces and Inheritance").

Suppose that you have a class that can use calligraphy to draw various types of data (strings, integers, and so on) and that contains a method for drawing each data type. It is cumbersome to use a new name for each method—for example, drawString , drawInteger , drawFloat , and so on. In the Java programming language, you can use the same name for all the drawing methods but pass a different argument list to each method. Thus, the data drawing class might declare four methods named draw , each of which has a different parameter list.

Overloaded methods are differentiated by the number and the type of the arguments passed into the method. In the code sample, draw(String s) and draw(int i) are distinct and unique methods because they require different argument types.

You cannot declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart.

The compiler does not consider return type when differentiating methods, so you cannot declare two methods with the same signature even if they have a different return type.

Java Challengers #1: Перегрузка методов в JVM

Добро пожаловать в серию статей Java Challengers! Этот серия статей посвящена особенностям программирования на Java. Их освоение — это ваш путь к становлению высококвалифицированным программистом на Java.

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

Готовы ли вы приступить к освоению основных концепций программирования на Java? Тогда давайте начнем с нашей первой задачки!

widening-boxing-varargs

Термин «Перегрузка методов»

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

Что такое перегрузка методов?

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

В Листинге 1 показаны методы с разными параметрами, которые различаются количеством, типом и порядком.

Листинг 1. Три варианта перегрузки методов.

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

В Листинге 1 вы видели примитивные типы int и double . Давайте отвлечёмся на минуту и вспомним примитивные типы в Java.

Таблица 1. Примитивные типы в Java

Тип Диапазон Значение по умолчанию Размер Примеры литералов
boolean true или false false 1 бит true, false
byte -128… 127 0 8 бит 1, -90, -128
char Символ юникода или от 0 до 65 536 \u0000 16 бит ‘a’, ‘\u0031’, ‘\201’, ‘\n’, 4
short -32,768… 32,767 0 16 бит 1, 3, 720, 22,000
int -2 147 483 648… 2 147 483 647 0 32 бит -2, -1, 0, 1, 9
long -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 0 64 бит -4000L, -900L, 10L, 700L
float 3.40282347 x 1038, 1.40239846 x 10-45 0.0 32 бит 1.67e200f, -1.57e-207f, .9f, 10.4F
double 1.7976931348623157 x 10308, 4.9406564584124654 x 10-324 0.0 64 бит 1.e700d, -123457e, 37e1d

Зачем мне использовать перегрузку методов?

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

В противоположность Листингу 1 представьте программу, где у вас будет много методов calculate() с именами похожими на calculate1 , calculate2 , calculate3 … не хорошо, правда? Перегрузка метода calculate() позволяет использовать одно и то же имя и изменять только то, что необходимо — параметры. Также очень легко найти перегруженные методы, поскольку они сгруппированы в коде.

Чем перегрузка не является

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

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

Перегрузка конструктора

Вы можете перегрузить конструктор таким же способом, как и метод:

Решите задачку по перегрузке методов

Готовы ли вы к первому испытанию? Давайте выясним!

Начните с внимательного изучения следующего кода.

Листинг 2. Сложная задача по перегрузке методов

Хорошо. Вы изучили код. Какой будет вывод?

  1. befe
  2. bfce
  3. efce
  4. aecf

Правильный ответ приведён в конце статьи.

Что сейчас произошло? Как JVM компилирует перегруженные методы

Для того чтобы понять что произошло в Листинге 2, вам нужно знать несколько вещей о том, как JVM компилирует перегруженные методы.

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

  1. Расширение (widening)
  2. Упаковка (autoboxing and unboxing)
  3. Аргументы переменной длины (varargs)

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

Вот пример расширения:

Это порядок расширения примитивных типов:

Порядок расширения примитивных типов

(Прим. переводчика — В JLS расширение примитивов описано с большими вариациями, например, long может быть расширен во float или в double.)

Обратите внимание, что происходит за кулисами при компиляции кода:

А вот пример распаковки:

Вот что происходит за кулисами при компиляции этого кода:

И вот пример метода с аргументами переменной длины. Обратите внимание, что методы переменной длины всегда являются последними для выполнения.

Что такое аргументы переменной длины?

Аргументы переменной длины — это просто массив значений, заданный трёмя точками (. ). Мы можем передать сколько угодно чисел int этому методу.

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

Расширение: практический пример

Когда мы передаем число 1 прямо в метод executeAction() , JVM автоматически интерпретирует его как int . Вот почему это число не будет передано в метод executeAction(short var) .

Аналогично, если мы передаём число 1.0 JVM автоматически распознает, что это double.

Конечно число 1.0 также может быть и float , но тип таких литералов предопредопределен. Поэтому в Листинге 2 выполняется метод executeAction(double var) .

Когда мы используем обёртку Double , есть два варианта: либо число может быть распаковано в примитивный тип, либо оно может быть расширено в Object . (Помните, что каждый класс в Java расширяет класс Object .) В этом случае JVM выбирает расширение типа Double в Object , потому что это требует меньше усилий, чем распаковка.

Последним мы передаём 1L и так как, мы указали тип — это long .

Распространенные ошибки с перегрузкой

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

Автоупаковка с обёртками (autoboxing with wrappers)

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

Автоупаковка будет работать только с типом double потому что, когда вы скомпилируете код, он будет эквивалентен этому:

Этот код скомпилируется. Первый int будет расширен до double и потом будет упакован в Double . Но при автоупаковке нет расширения типов и конструктор Double.valueof ожидает double , а не int . В этом случае автоупаковка будет работать, если мы сделаем явное приведение типа, например:

Помните, что Integer не может быть Long и Float и не может быть Double . Здесь нет наследования. Каждый из этих типов ( Integer , Long , Float , и Double ) — Number и Object .

Если Вы сомневаетесь, просто помните, что обёртки чисел (wrapper numbers) могут быть расширены до Number или Object . (Есть еще много чего, что можно сказать про обёртки, но оставим это для другой статьи.)

Литералы чисел в коде

Когда мы не указываем тип числа-литерала, JVM вычислит тип за нас. Если напрямую используем число 1 в коде, то JVM создаст его как int . Если мы попытаемся передать 1 напрямую в метод, который принимает short , то он не скомпилируется.

Такое же правило будет применяться, когда используется число 1.0 . Хотя это может быть и float , JVM будет считать его double .

Другой распространенной ошибкой является предположение, что Double или любая другая обертка лучше подойдет для метода, получающего double .

Факт в том, что JVM требуется меньше усилий для расширения обертки Double в Object вместо её распаковки в примитивный тип double .

Подводя итог, при использовании непосредственно в java-коде, 1 будет int и 1.0 будет double . Расширение — это самый лёгкий путь к выполнению, далее идёт упаковка или распаковка и последней операцией всегда будут методы переменной длины.

Как любопытный факт. Знаете ли вы, что тип char принимает числа?

Что необходимо помнить о перегрузке

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

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

Что следует иметь в виду: при перегрузке метода JVM сделает наименьшее усилие из возможных.

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

  • Первое — расширение (widening)
  • Второе — упаковка (boxing)
  • Третье — аргументы переменной длины (varargs)

Что следует учитывать: сложные ситуации возникают при объявлении чисел напрямую: 1 будет int и 1.0 будет double .

Также помните, что вы можете объявить эти типы явно, используя синтаксис 1F или 1f для float и 1D или 1d для double .

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

Ответ

Ответ к Листингу 2 — Вариант 3. efce.

Подробнее о перегрузке методов в Java

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

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

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

Методы, их параметры, взаимодействие и перегрузка

Методы, их параметры, взаимодействие и перегрузка - 1

И снова привет! В прошлой лекции мы познакомились с классами и конструкторами, и научились создавать собственные. Сегодня мы подробно познакомимся с такой неотъемлемой частью классов как методы. Метод — это совокупность команд, позволяющая выполнить некоторую операцию в программе. Иными словами, метод — это некоторая функция; что-то, что умеет делать твой класс. В других языках программирования методы часто называют “функциями”, но в Java слово “метод” прижилось больше:) В прошлой лекции, если помнишь, мы создавали простые методы для класса Cat, чтобы наши коты умели мяукать и прыгать: sayMeow() и jump() являются методами нашего класса. Результат их работы — вывод в консоль: Наши методы довольно просты: они просто выводят текст в консоль. Но в Java у методов есть главная задача — они должны выполнять действия над данными объекта . Менять значение данных объекта, преобразовывать их, выводить в консоль или делать с ними что-то другое. Наши текущие методы ничего не делают с данными объекта Cat . Давай рассмотрим более наглядный пример: К примеру, у нас есть класс, обозначающий грузовик — Truck . У прицепа грузовика есть длина, ширина и высота и вес (он будет нужен позже). В методе getVolume() мы совершаем вычисления — преобразуем данные нашего объекта к числу, которое обозначает объем (умножаем длину, ширину и высоту). Именно это число будет являться результатом метода. Обрати внимание — в описании метода написано public int getVolume . Это значит, что результатом работы этого метода обязательно должно быть число в виде int . Мы высчитали результат метода, и теперь должны вернуть его нашей программе, которая вызвала метод. Для того, чтобы вернуть результат метода в Java используется ключевое слово return .

Перегрузка методов в Java

Перегрузка методов в Java_vertex

Представим, что у нас есть такой код, в котором есть два метода с одинаковым названием:

Как Вы видите, тут есть два конструктора (если впервые слышите слово «конструктор», Вам следует почитать статью «Конструкторы в Java»). У них разные параметры, но называются они одинаково. У Вас выдает ошибку?

Нет.

Почему?

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

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

Зачем?

Вот, есть у меня в программе один метод print или один конструктор Dog. Зачем мне еще один?

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

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

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

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