Programmering

Metodeoverbelastning i JVM

Velkommen til det nye Java Challengers blogg! Denne bloggen er dedikert til utfordrende konsepter i Java-programmering. Mestre dem, og du vil være godt på vei til å bli en dyktig Java-programmerer.

Teknikkene i denne bloggen krever litt innsats for å mestre, men de vil utgjøre en stor forskjell i din daglige opplevelse som Java-utvikler. Det er lettere å unngå feil når du vet hvordan du skal bruke kjernen i Java-programmeringsteknikker, og sporing av feil er mye lettere når du vet nøyaktig hva som skjer på Java-koden din.

Er du klar til å mestre kjernekonsepter i Java-programmering? La oss så komme i gang med vår første Java Challenger!

Terminologi: Overbelastning av metoden

På grunn av begrepet overbelastning, utviklere har en tendens til å tro at denne teknikken vil overbelaste systemet, men det stemmer ikke. I programmering, metode overbelastning betyr å bruke samme metodenavn med forskjellige parametere.

Hva er metodeoverbelastning?

Metodeoverbelastning er en programmeringsteknikk som lar utviklere bruke samme metodenavn flere ganger i samme klasse, men med forskjellige parametere. I dette tilfellet sier vi at metoden er overbelastet. Oppføring 1 viser en enkelt metode hvis parametere er forskjellige i antall, type og rekkefølge.

Oppføring 1. Tre typer metodeoverbelastning

 Antall parametere: offentlig klasse Kalkulator {void calculate (int number1, int number2) {} ugyldig calc (int number1, int number2, int number3) {}} Type parametere: public class Calculator {void calc (int number1, int number2 ) {} ugyldig beregning (dobbelt tall1, dobbelt nummer2) {}} Parameterrekkefølge: offentlig klasse Kalkulator {ugyldig beregning (dobbelt tall1, int tall2) {} ugyldig beregning (int nummer1, dobbelt tall2) {}} 

Metodeoverbelastning og primitive typer

I liste 1 ser du de primitive typene int og dobbelt. Vi jobber mer med disse og andre typer, så ta et øyeblikk å gjennomgå de primitive typene i Java.

Tabell 1. Primitive typer i Java

TypeOmrådeMisligholdeStørrelseEksempel på bokstaver
boolsk sant eller usant falsk 1 bit sant, usant
byte -128 .. 127 0 8 biter 1, -90, 128
røye Unicode-tegn eller 0 til 65.536 \ u0000 16 bits 'a', '\ u0031', '\ 201', '\ n', 4
kort -32,768 .. 32,767 0 16 bits 1, 3, 720, 22,000
int -2,147,483,648 .. 2,147,483,647 0 32 biter -2, -1, 0, 1, 9
lang -9,223,372,036,854,775,808 til 9,223,372,036,854,775,807 0 64 bits -4000L, -900L, 10L, 700L
flyte 3.40282347 x 1038, 1.40239846 x 10-45 0.0 32 biter 1.67e200f, -1.57e-207f, .9f, 10.4F
dobbelt

1.7976931348623157 x 10308, 4.9406564584124654 x 10-324

 0.0 64 bits 1.e700d, -123457e, 37e1d

Hvorfor skal jeg bruke metodeoverbelastning?

Overbelastning gjør koden renere og lettere å lese, og det kan også hjelpe deg med å unngå feil i programmene dine.

I motsetning til oppføring 1, forestill deg et program der du hadde flere regne ut() metoder med navn som regne ut1, beregne2, beregne3 . . . ikke bra, ikke sant? Overbelastning av regne ut() metoden lar deg bruke samme metodenavn mens du bare endrer det som må endres: parametrene. Det er også veldig enkelt å finne overbelastede metoder fordi de er gruppert sammen i koden din.

Hva overbelastning er ikke

Vær oppmerksom på at du endrer navnet på en variabel er ikke overbelastning. Følgende kode kompileres ikke:

 offentlig klasse Kalkulator {void calculate (int firstNumber, int secondNumber) {} void calculate (int secondNumber, int thirdNumber) {}} 

Du kan heller ikke overbelaste en metode ved å endre returtypen i metodesignaturen. Følgende kode vil heller ikke kompileres:

 offentlig klasse Kalkulator {dobbel beregne (int tall1, int tall2) {retur 0,0;} lang beregne (int tall1, int nummer2) {retur 0;}} 

Overbelastning av konstruktør

Du kan overbelaste en konstruktør på samme måte som en metode:

 offentlig klasse Kalkulator {privat int nummer1; privat int nummer2; public Calculator (int number1) {this.number1 = number1;} public Calculator (int number1, int number2) {this.number1 = number1; dette.nummer2 = nummer2; }} 

Ta metoden overbelastning utfordring!

Er du klar for din første Java Challenger? La oss finne det ut!

Start med å nøye gjennomgå følgende kode.

Oppføring 2. Avansert metode for overbelastningsutfordring

 offentlig klasse AdvancedOverloadingChallenge3 {statisk streng x = ""; public static void main (String ... doYourBest) {executeAction (1); executeAction (1.0); executeAction (Double.valueOf ("5")); executeAction (1L); System.out.println (x); } statisk tomrom executeAction (int ... var) {x + = "a"; } statisk tomrom executeAction (Heltall var) {x + = "b"; } statisk tomrom executeAction (Object var) {x + = "c"; } statisk tomrom executeAction (kort var) {x + = "d"; } statisk tomrom executeAction (float var) {x + = "e"; } statisk tomrom executeAction (dobbel var) {x + = "f"; }} 

Ok, du har vurdert koden. Hva er produksjonen?

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

Sjekk svaret ditt her.

Hva skjedde nå? Hvordan JVM kompilerer overbelastede metoder

For å forstå hva som skjedde i Listing 2, må du vite noen ting om hvordan JVM kompilerer overbelastede metoder.

Først av alt er JVM det intelligent lat: det vil alltid anstrenge seg minst mulig for å utføre en metode. Når du tenker på hvordan JVM håndterer overbelastning, må du huske på tre viktige kompileringsteknikker:

  1. Utvidende
  2. Boksing (autoboksing og unboxing)
  3. Varargs

Hvis du aldri har møtt disse tre teknikkene, bør noen få eksempler bidra til å gjøre dem tydelige. Merk at JVM utfører dem i bestillingen gitt.

Her er et eksempel på utvidende:

 int primitiveIntNumber = 5; dobbelt primitiveDoubleNumber = primitiveIntNumber; 

Dette er rekkefølgen til de primitive typene når de utvides:

Rafael del Nero

Her er et eksempel på autoboksing:

 int primitiveIntNumber = 7; Integer wrapperIntegerNumber = primitiveIntNumber; 

Legg merke til hva som skjer bak kulissene når denne koden blir samlet:

 Integer wrapperIntegerNumber = Integer.valueOf (primitiveIntNumber); 

Og her er et eksempel påunboxing:

 Integer wrapperIntegerNumber = 7; int primitiveIntNumber = wrapperIntegerNumber; 

Dette er hva som skjer bak kulissene når denne koden blir samlet:

 int primitiveIntNumber = wrapperIntegerNumber.intValue (); 

Og her er et eksempel på varargs; noter det varargs er alltid den siste som blir henrettet:

 utfør (int ... tall) {} 

Hva er Varargs?

Brukes til variable argumenter, varargs er i utgangspunktet en rekke verdier spesifisert av tre prikker (...) Vi kan passere hvor mange som helst int tallene vi ønsker å denne metoden.

For eksempel:

utføre (1,3,4,6,7,8,8,6,4,6,88 ...); // Vi kunne fortsette ... 

Varargs er veldig nyttig fordi verdiene kan overføres direkte til metoden. Hvis vi brukte matriser, måtte vi samle arrayet med verdiene.

Utvidelse: Et praktisk eksempel

Når vi sender nummer 1 direkte til executeAction metode, behandler JVM den automatisk som en int. Det er derfor tallet ikke går til executeAction (kort var) metode.

På samme måte, hvis vi passerer tallet 1.0, gjenkjenner JVM automatisk tallet som et dobbelt.

Selvfølgelig kan tallet 1.0 også være en flyte, men typen er forhåndsdefinert. Det er derfor executeAction (dobbel var) metoden blir påkalt i Listing 2.

Når vi bruker Dobbelt innpakningstype, det er to muligheter: enten innpakningsnummeret kan være utpakket til en primitiv type, eller det kan utvides til en Gjenstand. (Husk at hver klasse i Java utvider Gjenstand klasse.) I så fall velger JVM å utvide Dobbelt skriv til en Gjenstand fordi det krever mindre innsats enn unboxing ville, som jeg forklarte tidligere.

Det siste tallet vi passerer er 1 liter, og fordi vi har spesifisert variabeltypen denne gangen, er det det lang.

Videoutfordring! Feilsøking metode overbelastning

Feilsøking er en av de enkleste måtene å fullt ut absorbere programmeringskonsepter samtidig som du forbedrer koden din. I denne videoen kan du følge med mens jeg feilsøker og forklarer metoden for overbelastningsutfordring:

Vanlige feil med overbelastning

Nå har du sannsynligvis funnet ut at ting kan bli vanskelig med overbelastning av metoden, så la oss vurdere noen av utfordringene du sannsynligvis vil møte.

Autoboksing med innpakninger

Java er et sterkt skrevet programmeringsspråk, og når vi bruker autoboksing med innpakninger, er det noen ting vi må huske på. For det første kompileres ikke følgende kode:

 int primitiveIntNumber = 7; Dobbelt wrapperNumber = primitiveIntNumber; 

Autoboksing fungerer bare med dobbelt skriv fordi det som skjer når du kompilerer denne koden er det samme som følgende:

 Dobbeltnummer = Double.valueOf (primitiveIntNumber); 

Ovennevnte kode vil kompilere. Den førsteint typen blir utvidet til dobbelt og så blir det bokset til Dobbelt. Men når autoboksing er det ingen type utvidelse og konstruktøren fra Double.valueOf vil motta en dobbelt, ikke en int. I dette tilfellet vil autoboksing bare fungere hvis vi bruker en rollebesetting, slik:

 Double wrapperNumber = (double) primitiveIntNumber; 

Husk atHeltall Kan ikke være Lang og Flyte Kan ikke være Dobbelt. Det er ingen arv. Hver av disse typene--Heltall, Lang, Flyte, og Dobbelt - eren Nummer og en Gjenstand.

Når du er i tvil, er det bare å huske at innpakningstallene kan utvides til Nummer eller Gjenstand. (Det er mye mer å utforske om innpakninger, men jeg vil legge igjen det til et annet innlegg.)

Hardkodede nummertyper i JVM

Når vi ikke spesifiserer en type til et tall, vil JVM gjøre det for oss. Hvis vi bruker nummer 1 direkte i koden, vil JVM opprette det som et int. Hvis du prøver å gi 1 direkte til en metode som mottar en kort, vil den ikke kompilere.

For eksempel:

 class Calculator {public static void main (String ... args) {// Denne metoden kan ikke kompileres // Ja, 1 kan være char, kort, byte, men JVM oppretter den som en int-beregning (1); } ugyldig beregne (kort tall) {}} 

Den samme regelen blir brukt når du bruker tallet 1.0; selv om det kan være en flyte, vil JVM behandle dette tallet som en dobbelt:

 class Calculator {public static void main (String ... args) {// Denne metoden kan ikke kompileres // Ja, 1 kan være flytende, men JVM oppretter den som dobbeltberegning (1.0); } ugyldig beregning (flytnummer) {}} 

En annen vanlig feil er å tro at Dobbelt eller hvilken som helst annen innpakningstype, vil være bedre egnet til metoden som mottar en dobbelt. Det tar faktisk mindre innsats for JVM å utvide de Dobbelt innpakning til en Gjenstand i stedet for å pakke den ut til en dobbelt primitiv type.

For å oppsummere, når det brukes direkte i Java-kode, vil 1 være int og 1.0 vil være dobbelt. Utvidelse er den lateste veien til utførelse, boksing eller unboxing kommer neste, og den siste operasjonen vil alltid være varargs.

Som et merkelig faktum, visste du at røye type aksepterer tall?

 char anyChar = 127; // Ja, dette er rart, men det kompilerer 

Hva du skal huske på overbelastning

Overbelastning er en veldig kraftig teknikk for scenarier der du trenger samme metodenavn med forskjellige parametere. Det er en nyttig teknikk fordi det å ha det riktige navnet i koden din stor forskjell for lesbarhet. I stedet for å duplisere metoden og legge til rot i koden din, kan du bare overbelaste den. Å gjøre dette holder koden ren og lett å lese, og det reduserer risikoen for at duplikatmetoder vil ødelegge en del av systemet.

Hva du må huske på: Ved overbelastning av en metode vil JVM gjøre minst mulig innsats; dette er rekkefølgen på den lateste veien til henrettelse:

  • Først utvides
  • For det andre er boksing
  • Tredje er Varargs

Hva du skal passe på: Vanskelige situasjoner vil oppstå ved å erklære et nummer direkte: 1 vil være int og 1.0 blir dobbelt.

Husk også at du kan erklære disse typene eksplisitt ved hjelp av syntaksen 1F eller 1f for a flyte eller 1D eller 1d for en dobbelt.

Dette avslutter vår første Java Challenger, der vi introduserer JVMs rolle i metodeoverbelastning. Det er viktig å innse at JVM er iboende lat, og alltid vil følge den lateste veien til henrettelse.

 

Fasit

Svaret på Java Challenger i Listing 2 er: Alternativ 3. efce.

Mer om metodeoverbelastning i Java

  • Java 101: Klasser og objekter i Java: En ekte nybegynnerintroduksjon til klasser og objekter, inkludert korte seksjoner om metoder og metodeoverbelastning.
  • Java 101: Elementære Java-språkfunksjoner: Lær mer om hvorfor det betyr noe at Java er et sterkt skrevet språk og få en full introduksjon til primitive typer i Java.
  • For mange parametere i Java-metoder, del 4: Utforsk begrensningene og ulempene ved metodeoverbelastning, og hvordan de kan løses ved å integrere tilpassede typer og parameterobjekter.

Denne historien, "Method overloading in the JVM" ble opprinnelig utgitt av JavaWorld.