Programování

Přetížení metody v JVM

Vítejte v novém Vyzyvatelé jazyka Java blog! Tento blog je věnován náročným konceptům v programování v Javě. Zvládněte je a budete na dobré cestě stát se vysoce kvalifikovaným programátorem Java.

Techniky v tomto blogu vyžadují určité úsilí, aby je zvládli, ale budou mít zásadní rozdíl ve vašem každodenním používání jako vývojář Java. Vyhýbání se chybám je jednodušší, když víte, jak správně aplikovat základní programovací techniky Java, a sledování chyb je mnohem snazší, když víte přesně, co se děje ve vašem kódu Java.

Jste připraveni začít ovládat základní koncepty v programování Java? Začněme s naším prvním Java Challengerem!

Terminologie: Přetížení metody

Kvůli termínu přetížení, vývojáři mají tendenci si myslet, že tato technika přetíží systém, ale to není pravda. V programování přetížení metody znamená použití stejného názvu metody s různými parametry.

Co je přetížení metody?

Přetížení metody je programovací technika, která umožňuje vývojářům používat stejný název metody vícekrát ve stejné třídě, ale s různými parametry. V tomto případě říkáme, že metoda je přetížená. Výpis 1 zobrazuje jedinou metodu, jejíž parametry se liší počtem, typem a uspořádáním.

Výpis 1. Tři typy přetížení metody

 Počet parametrů: public class Calculator {void spočítat (int number1, int number2) {} vyprázdnit výpočet (int number1, int number2, int number3) {}} Typ parametrů: public class Calculator {void spočítat (int číslo1, int číslo2 ) {} výpočet prázdnoty (dvojité číslo1, dvojité číslo2) {}} Pořadí parametrů: kalkulačka veřejné třídy {výpočet prázdnoty (dvojité číslo1, int číslo2) {} výpočet prázdnoty (int číslo1, dvojité číslo2) {}} 

Přetížení metody a primitivní typy

V seznamu 1 uvidíte primitivní typy int a dvojnásobek. S těmito a dalšími typy budeme více pracovat, takže si chvilku prostudujte primitivní typy v Javě.

Tabulka 1. Primitivní typy v Javě

TypRozsahVýchozíVelikostUkázkové literály
booleovský pravda nebo lež Nepravdivé 1 bit pravda, nepravda
byte -128 .. 127 0 8 bitů 1, -90, 128
char Znak Unicode nebo 0 až 65 536 \ u0000 16 bitů 'a', '\ u0031', '\ 201', '\ n', 4
krátký -32,768 .. 32,767 0 16 bitů 1, 3, 720, 22,000
int -2,147,483,648 .. 2,147,483,647 0 32 bitů -2, -1, 0, 1, 9
dlouho -9 223 372 036 854 775 808 až 9 223 372 036 854 775 807 0 64 bitů -4000L, -900L, 10L, 700L
plovák 3,40282347 x 1038, 1,40239846 x 10-45 0.0 32 bitů 1,67e200f, -1,57e-207f, 0,9f, 10,4F
dvojnásobek

1,7976931348623157 x 10308, 4,9406564584124654 x 10-324

 0.0 64 bitů 1.e700d, -123457e, 37e1d

Proč bych měl používat přetížení metody?

Díky přetížení je váš kód čistší a snáze čitelný a může vám také pomoci vyhnout se chybám ve vašich programech.

Na rozdíl od Výpisu 1 si představte program, kde jste měli více vypočítat() metody s názvy jako vypočítat1, vypočítat2, vypočítat3 . . . není dobré, že? Přetížení vypočítat() metoda umožňuje použít stejný název metody a přitom měnit pouze to, co je třeba změnit: parametry. Je také velmi snadné najít přetížené metody, protože jsou seskupeny ve vašem kódu.

Co přetížení není

Uvědomte si, že změna názvu proměnné není přetížení. Následující kód nebude kompilován:

 public class Calculator {void spočítat (int firstNumber, int secondNumber) {} void spočítat (int secondNumber, int thirdNumber) {}} 

Metodu také nemůžete přetížit změnou typu návratu v podpisu metody. Následující kód se nebude kompilovat:

 public class Calculator {dvojitý výpočet (int číslo 1, int číslo 2) {návrat 0,0;} dlouhý výpočet (int číslo 1, int číslo 2) {návrat 0;}} 

Přetížení konstruktoru

Konstruktor můžete přetížit stejným způsobem jako metodu:

 public class Calculator {private int number1; soukromé int číslo 2; veřejná kalkulačka (int číslo1) {this.number1 = číslo1;} veřejná kalkulačka (int číslo1, int číslo2) {this.number1 = číslo1; this.number2 = number2; }} 

Přijměte výzvu přetížení metody!

Jste připraveni na svůj první Java Challenger? Pojďme to zjistit!

Začněte pečlivou kontrolou následujícího kódu.

Výpis 2. Výzva k přetížení pokročilých metod

 veřejná třída AdvancedOverloadingChallenge3 {statický řetězec x = ""; public static void main (String ... doYourBest) {executeAction (1); executeAction (1.0); executeAction (Double.valueOf ("5")); executeAction (1L); System.out.println (x); } static void executeAction (int ... var) {x + = "a"; } static void executeAction (Celé číslo var) {x + = "b"; } static void executeAction (Object var) {x + = "c"; } static void executeAction (krátká var) {x + = "d"; } static void executeAction (float var) {x + = "e"; } static void executeAction (dvojitá var) {x + = "f"; }} 

Dobře, zkontrolovali jste kód. Jaký je výstup?

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

Zkontrolujte svou odpověď zde.

Co se právě stalo? Jak JVM kompiluje přetížené metody

Abychom pochopili, co se stalo ve Výpisu 2, potřebujete vědět některé věci o tom, jak JVM kompiluje přetížené metody.

Nejprve je to JVM inteligentně líný: k provedení metody bude vždy vynaloženo co nejmenší úsilí. Když tedy přemýšlíte o tom, jak JVM zpracovává přetížení, mějte na paměti tři důležité techniky kompilátoru:

  1. Rozšíření
  2. Box (autoboxing a unboxing)
  3. Varargs

Pokud jste se s těmito třemi technikami nikdy nesetkali, mělo by vám je objasnit několik příkladů. Všimněte si, že je JVM provádí v uvedeném pořadí.

Zde je příklad rozšiřování:

 int primitiveIntNumber = 5; double primitiveDoubleNumber = primitiveIntNumber; 

Toto je pořadí primitivních typů, když jsou rozšířeny:

Rafael del Nero

Zde je příklad autoboxing:

 int primitiveIntNumber = 7; Celé číslo wrapperIntegerNumber = primitiveIntNumber; 

Všimněte si, co se děje v zákulisí, když je tento kód kompilován:

 Integer wrapperIntegerNumber = Integer.valueOf (primitiveIntNumber); 

A tady je příkladrozbalení:

 Celé číslo wrapperIntegerNumber = 7; int primitiveIntNumber = wrapperIntegerNumber; 

Při kompilaci tohoto kódu se děje v zákulisí:

 int primitiveIntNumber = wrapperIntegerNumber.intValue (); 

A tady je příklad varargy; Všimněte si, že varargy je vždy poslední, kdo má být proveden:

 vykonat (int… čísla) {} 

Co je to Varargs?

Používá se pro proměnné argumenty, varargy je v podstatě pole hodnot specifikovaných třemi tečkami (…) Můžeme projít jakkoli mnoho int čísla, která chceme pro tuto metodu.

Například:

vykonat (1,3,4,6,7,8,8,6,4,6,88 ...); // Mohli bychom pokračovat ... 

Varargs je velmi užitečný, protože hodnoty lze předat přímo metodě. Pokud bychom používali pole, museli bychom vytvořit instanci pole s hodnotami.

Rozšíření: Praktický příklad

Když předáme číslo 1 přímo k provést akci metoda, JVM s ní automaticky zachází jako int. Proto číslo nepřijde na executeAction (krátká var) metoda.

Podobně, pokud předáme číslo 1,0, JVM automaticky rozpozná toto číslo jako a dvojnásobek.

Číslo 1.0 by samozřejmě mohlo být také a plovák, ale typ je předdefinován. Proto executeAction (dvojitá var) metoda je vyvolána v seznamu 2.

Když používáme Dvojnásobek typ obálky, existují dvě možnosti: buď může být číslo obálky rozbaleno na primitivní typ, nebo může být rozšířeno na Objekt. (Pamatujte, že každá třída v Javě rozšiřuje Objekt V takovém případě se JVM rozhodne obejít Dvojnásobek zadejte do Objekt protože to vyžaduje menší úsilí, než by to mělo unboxing, jak jsem vysvětlil dříve.

Poslední číslo, které projdeme, je 1L, a protože jsme tentokrát určili typ proměnné, je dlouho.

Video výzva! Přetížení metody ladění

Ladění je jedním z nejjednodušších způsobů, jak plně absorbovat programovací koncepty a zároveň vylepšit váš kód. V tomto videu můžete sledovat, zatímco ladím a vysvětluji výzvu přetížení metody:

Časté chyby s přetížením

Nyní jste pravděpodobně přišli na to, že s přetížením metod se mohou věci zkomplikovat, takže pojďme zvážit několik výzev, na které pravděpodobně narazíte.

Autoboxing s obaly

Java je silně napsaný programovací jazyk, a když používáme autoboxing s obaly, musíme mít na paměti některé věci. Za prvé, následující kód nebude kompilován:

 int primitiveIntNumber = 7; Double wrapperNumber = primitiveIntNumber; 

Autoboxing bude fungovat pouze s dvojnásobek zadejte, protože to, co se stane při kompilaci tohoto kódu, je stejné jako následující:

 Double number = Double.valueOf (primitiveIntNumber); 

Výše uvedený kód bude kompilován. Prvníint typ bude rozšířen na dvojnásobek a poté to bude orámováno Dvojnásobek. Ale při autoboxingu neexistuje žádné rozšíření typu a konstruktor z Double.valueOf obdrží a dvojnásobek, ne int. V tomto případě by autoboxing fungoval pouze tehdy, kdybychom použili obsazení, například:

 Double wrapperNumber = (double) primitiveIntNumber; 

Pamatuj si toCelé číslo nemůže být Dlouho a Plovák nemůže být Dvojnásobek. Neexistuje žádné dědictví. Každý z těchto typů -Celé číslo, Dlouho, Plovák, a Double - jeA Číslo a Objekt.

Pokud si nejste jistí, nezapomeňte, že lze počet obálek rozšířit na Číslo nebo Objekt. (O obálkách je toho možné prozkoumat mnohem víc, ale nechám to na další příspěvek.)

Napevno číslované typy čísel v JVM

Když neurčíme typ čísla, JVM to udělá za nás. Pokud použijeme číslo 1 přímo v kódu, JVM jej vytvoří jako int. Pokud se pokusíte předat 1 přímo metodě, která přijímá a krátký, nebude se kompilovat.

Například:

 class Calculator {public static void main (String… args) {// Tato metoda vyvolání nebude kompilovat // Ano, 1 může být char, short, byte, ale JVM jej vytvoří jako int count (1); } výpočet neplatnosti (krátké číslo) {}} 

Stejné pravidlo se použije při použití čísla 1,0; i když by to mohlo být plovákbude JVM považovat toto číslo za a dvojnásobek:

 class Calculator {public static void main (String ... args) {// Tato metoda vyvolání nebude kompilovat // Ano, 1 by mohl být float, ale JVM jej vytvoří jako dvojitý výpočet (1.0); } výpočet neplatnosti (float number) {}} 

Další častou chybou je myslet si, že Dvojnásobek nebo jakýkoli jiný typ obálky by byl vhodnější pro metodu, která přijímá dvojnásobek. Ve skutečnosti to JVM vyžaduje méně úsilí rozšířit the Dvojnásobek obal na Objekt namísto rozbalení do a dvojnásobek primitivní typ.

Stručně řečeno, při použití přímo v kódu Java bude 1 int a 1.0 bude dvojnásobek. Widening je nejlínější cesta k provedení, na rad přichází box nebo unboxing a poslední operace bude vždy varargy.

Jako zvláštní skutečnost jste věděli, že char typ přijímá čísla?

 char anyChar = 127; // Ano, je to divné, ale kompiluje se 

Co si pamatovat o přetížení

Přetížení je velmi účinná technika pro scénáře, kde potřebujete stejný název metody s různými parametry. Je to užitečná technika, protože mít v kódu správný název dělá velký rozdíl v čitelnosti. Spíše než duplikovat metodu a přidat do kódu nepořádek, můžete ji jednoduše přetížit. Díky tomu bude váš kód čistý a snadno čitelný a sníží se riziko, že duplicitní metody rozbijí nějakou část systému.

Co je třeba mít na paměti: Při přetížení metody vynaloží JVM co nejmenší úsilí; toto je pořadí nejlínější cesty k provedení:

  • První se rozšiřuje
  • Druhým je box
  • Třetí je Varargs

Na co si dát pozor: Těžké situace nastanou přímým prohlášením čísla: 1 bude int a 1.0 bude dvojnásobek.

Nezapomeňte, že tyto typy můžete explicitně deklarovat pomocí syntaxe 1F nebo 1f pro a plovák nebo 1D nebo 1d pro a dvojnásobek.

Tím končí náš první Java Challenger, představující roli JVM v přetížení metod. Je důležité si uvědomit, že JVM je ze své podstaty líný a vždy bude následovat nejlínější cestu k provedení.

 

Odpovědět klíč

Odpověď na Java Challenger v seznamu 2 je: Možnost 3. efce.

Více o přetížení metody v Javě

  • Java 101: Classes and objects in Java: A Skutočný začátečník Úvod do tříd a objektů, včetně krátkých sekcí o metodách a přetížení metod.
  • Java 101: Základní funkce jazyka Java: Zjistěte více o tom, proč je důležité, že Java je silně psaný jazyk, a získejte úplný úvod do primitivních typů v Javě.
  • Příliš mnoho parametrů v metodách Java, Část 4: Prozkoumejte omezení a nevýhody přetížení metody a jak je lze napravit integrací vlastních typů a objektů parametrů.

Tento příběh „Přetížení metody v JVM“ původně publikoval JavaWorld.