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ě
Typ | Rozsah | Výchozí | Velikost | Uká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čítat
1, 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?
- befe
- bfce
- efce
- 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:
- Rozšíření
- Box (autoboxing a unboxing)
- 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 NeroZde 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 - je
A Čí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ák
bude 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.