Programmering

Metodeoverbelastning i JVM

Velkommen til det nye Java udfordrere blog! Denne blog er dedikeret til udfordrende koncepter inden for Java-programmering. Mestre dem, og du vil være godt på vej til at blive en meget dygtig Java-programmør.

Teknikkerne i denne blog kræver en vis indsats for at mestre, men de vil gøre en stor forskel i din daglige oplevelse som Java-udvikler. Det er lettere at undgå bugs, når du ved, hvordan du korrekt anvender Java-programmeringsteknikker korrekt, og det er meget lettere at spore bugs, når du ved præcis, hvad der sker på din Java-kode.

Er du klar til at begynde at mestre kernekoncepter i Java-programmering? Lad os så komme i gang med vores første Java Challenger!

Terminologi: Metodeoverbelastning

På grund af udtrykket overbelastning, udviklere har tendens til at tro, at denne teknik vil overbelaste systemet, men det er ikke sandt. I programmering, metode overbelastning betyder at bruge samme metode navn med forskellige parametre.

Hvad er metodeoverbelastning?

Metodeoverbelastning er en programmeringsteknik, der giver udviklere mulighed for at bruge det samme metodenavn flere gange i samme klasse, men med forskellige parametre. I dette tilfælde siger vi, at metoden er overbelastet. Liste 1 viser en enkelt metode, hvis parametre adskiller sig i antal, type og rækkefølge.

Notering 1. Tre typer metodeoverbelastning

 Antal parametre: offentlig klasse Lommeregner {ugyldig beregning (int nummer1, int nummer2) {} ugyldig beregning (int nummer1, int antal2, int nummer3) {}} Parametertype: offentlig klasse regnemaskine {ugyldig beregning (int nummer1, int nummer2 ) {} ugyldig beregning (dobbelt nummer1, dobbelt tal2) {}} Parameterrækkefølge: offentlig klasse-regnemaskine 

Metodeoverbelastning og primitive typer

I liste 1 ser du de primitive typer int og dobbelt. Vi arbejder mere med disse og andre typer, så tag et øjeblik på at gennemgå de primitive typer i Java.

Tabel 1. Primitive typer i Java

TypeRækkeviddeStandardStørrelseEksempel på bogstaver
boolsk sandt eller falsk falsk 1 bit sandt falsk
byte -128 .. 127 0 8 bits 1, -90, 128
char 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 bits -2, -1, 0, 1, 9
lang -9.223.372.036.854.775.808 til 9.223.372.036.854.775.807 0 64 bit -4000L, -900L, 10L, 700L
flyde 3.40282347 x 1038, 1.40239846 x 10-45 0.0 32 bits 1,67e200f, -1,57e-207f, .9f, 10,4F
dobbelt

1.7976931348623157 x 10308, 4.9406564584124654 x 10-324

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

Hvorfor skal jeg bruge metodeoverbelastning?

Overbelastning gør din kode renere og lettere at læse, og det kan også hjælpe dig med at undgå fejl i dine programmer.

I modsætning til liste 1, forestil dig et program, hvor du havde flere Beregn() metoder med navne som Beregn1, beregne2, beregne3 . . . ikke godt, ikke? Overbelastning af Beregn() metode lader dig bruge det samme metodenavn, mens du kun ændrer det, der skal ændres: parametrene. Det er også meget let at finde overbelastede metoder, fordi de er samlet i din kode.

Hvilken overbelastning er ikke

Vær opmærksom på, at du ændrer navnet på en variabel er ikke overbelastning. Følgende kode kompileres ikke:

 offentlig klasse Lommeregner {ugyldig beregne (int firstNumber, int secondNumber) {} ugyldig beregne (int secondNumber, int thirdNumber) {}} 

Du kan heller ikke overbelaste en metode ved at ændre returtypen i metodesignaturen. Den følgende kode kompileres heller ikke:

 offentlig klasse Lommeregner {dobbeltberegning (int-nummer1, int-nummer2) {returnering 0,0;} lang beregning (int-nummer1, int-nummer2) {retur 0;}} 

Konstruktør overbelastning

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

 public class Calculator {privat int nummer1; privat int nummer2; public Calculator (int number1) {this.number1 = number1;} public Calculator (int number1, int number2) {this.number1 = number1; dette.nummer2 = antal2; }} 

Tag metoden overbelastning udfordring!

Er du klar til din første Java Challenger? Lad os finde ud af det!

Start med nøje at gennemgå følgende kode.

Notering 2. Avanceret metode til overbelastningsudfordring

 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 ugyldighed executeAction (int ... var) {x + = "a"; } statisk ugyldighed executeAction (heltal var) {x + = "b"; } statisk ugyldighed executeAction (Objekt var) {x + = "c"; } statisk ugyldighed executeAction (kort var) {x + = "d"; } statisk ugyldighed executeAction (float var) {x + = "e"; } statisk ugyldighed executeAction (dobbelt var) {x + = "f"; }} 

Okay, du har gennemgået koden. Hvad er output?

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

Tjek dit svar her.

Hvad skete der lige? Hvordan JVM kompilerer overbelastede metoder

For at forstå hvad der skete i Listing 2, skal du vide nogle ting om, hvordan JVM kompilerer overbelastede metoder.

Først og fremmest er JVM det intelligent doven: det vil altid udøve mindst mulig indsats for at udføre en metode. Når du overvejer, hvordan JVM håndterer overbelastning, skal du huske på tre vigtige kompileringsteknikker:

  1. Udvidelse
  2. Boksning (autoboxing og unboxing)
  3. Varargs

Hvis du aldrig har stødt på disse tre teknikker, bør et par eksempler hjælpe med at gøre dem klare. Bemærk, at JVM udfører dem i den angivne rækkefølge.

Her er et eksempel på udvidelse:

 int primitiveIntNumber = 5; dobbelt primitiveDoubleNumber = primitiveIntNumber; 

Dette er rækkefølgen af ​​de primitive typer, når de udvides:

Rafael del Nero

Her er et eksempel på autoboxing:

 int primitiveIntNumber = 7; Integer wrapperIntegerNumber = primitiveIntNumber; 

Bemærk hvad der sker bag kulisserne, når denne kode er kompileret:

 Integer wrapperIntegerNumber = Integer.valueOf (primitiveIntNumber); 

Og her er et eksempel påunboxing:

 Integer wrapperIntegerNumber = 7; int primitiveIntNumber = wrapperIntegerNumber; 

Her er hvad der sker bag kulisserne, når denne kode er kompileret:

 int primitiveIntNumber = wrapperIntegerNumber.intValue (); 

Og her er et eksempel på varargs; Noter det varargs er altid den sidste, der udføres:

 udfør (int ... numre) {} 

Hvad er varargs?

Bruges til variable argumenter, varargs er dybest set en række værdier, der er specificeret af tre prikker (...) Vi kan passere, hvor mange som helst int tal, vi ønsker at denne metode.

For eksempel:

udføre (1,3,4,6,7,8,8,6,4,6,88 ...); // Vi kunne fortsætte ... 

Varargs er meget praktisk, fordi værdierne kan overføres direkte til metoden. Hvis vi brugte arrays, ville vi være nødt til at instantiere arrayet med værdierne.

Udvidelse: Et praktisk eksempel

Når vi sender nummer 1 direkte til executeAction metode behandler JVM den automatisk som en int. Derfor går antallet ikke til executeAction (kort var) metode.

Tilsvarende, hvis vi videregiver nummeret 1.0, genkender JVM automatisk dette nummer som et dobbelt.

Naturligvis kan tallet 1.0 også være en flyde, men typen er foruddefineret. Det er derfor executeAction (dobbelt var) metode påberåbes i liste 2.

Når vi bruger Dobbelt indpakningstype, der er to muligheder: enten indpakningsnummeret kunne være udpakket til en primitiv type, eller det kunne udvides til en Objekt. (Husk at hver klasse i Java udvider Objekt klasse.) I så fald vælger JVM at udvide Dobbelt skriv til en Objekt fordi det kræver mindre indsats end unboxing ville, som jeg forklarede før.

Det sidste tal, vi videregiver, er 1 liter, og fordi vi har specificeret variabeltypen denne gang, er det lang.

Video udfordring! Fejlretningsmetode overbelastning

Fejlfinding er en af ​​de nemmeste måder til fuldt ud at absorbere programmeringskoncepter, samtidig med at du forbedrer din kode. I denne video kan du følge med, mens jeg debugger og forklarer metoden for overbelastningsudfordring:

Almindelige fejl med overbelastning

Nu har du sandsynligvis fundet ud af, at ting kan blive vanskelige med overbelastning af metoder, så lad os overveje et par af de udfordringer, du sandsynligvis vil støde på.

Autoboxing med indpakninger

Java er et stærkt skrevet programmeringssprog, og når vi bruger autoboxing med indpakninger, er der nogle ting, vi skal huske på. For det første kompileres følgende kode ikke:

 int primitiveIntNumber = 7; Dobbelt wrapperNumber = primitiveIntNumber; 

Autoboxing fungerer kun med dobbelt skriv, fordi hvad der sker, når du kompilerer denne kode, er det samme som følgende:

 Dobbeltnummer = Double.valueOf (primitiveIntNumber); 

Ovenstående kode kompileres. Den førsteint type udvides til dobbelt og så vil det blive bokset til Dobbelt. Men når autoboxing er der ingen type udvidelse, og konstruktøren fra Double.valueOf modtager en dobbelt, ikke en int. I dette tilfælde fungerer autoboxing kun, hvis vi anvender en rollebesætning, sådan:

 Double wrapperNumber = (dobbelt) primitiveIntNumber; 

Huske på, atHeltal kan ikke være Lang og Flyde kan ikke være Dobbelt. Der er ingen arv. Hver af disse typer--Heltal, Lang, Flydeog Dobbelt - er-en Nummer og en Objekt.

Når du er i tvivl, skal du bare huske at indpakningsnumrene kan udvides til Nummer eller Objekt. (Der er meget mere at udforske om indpakninger, men jeg vil lade det være til et andet indlæg.)

Hårdkodede nummertyper i JVM

Når vi ikke angiver en type til et nummer, vil JVM gøre det for os. Hvis vi bruger nummer 1 direkte i koden, opretter JVM det som et int. Hvis du prøver at videregive 1 direkte til en metode, der modtager en kort, det kompilerer ikke.

For eksempel:

 class Calculator {public static void main (String… args) {// Denne metodeopkald kompileres ikke // Ja, 1 kunne være char, kort, byte, men JVM opretter den som en int-beregning (1); } ugyldigt beregne (kort tal) {}} 

Den samme regel anvendes, når du bruger tallet 1.0; selvom det kunne være en flyde, JVM behandler dette nummer som en dobbelt:

 class Calculator {public static void main (String ... args) {// Denne metodeopkald vil ikke kompilere // Ja, 1 kunne være float, men JVM opretter det som dobbeltberegning (1.0); } ugyldigt beregne (flydende nummer) {}} 

En anden almindelig fejl er at tro, at Dobbelt eller enhver anden indpakningstype ville være bedre egnet til den metode, der modtager en dobbelt. Faktisk tager det mindre indsats for JVM at udvide det Dobbelt indpakning til en Objekt i stedet for at afkasse den til en dobbelt primitiv type.

For at opsummere, når det bruges direkte i Java-kode, vil 1 være int og 1.0 vil være dobbelt. Udvidelse er den lateste vej til udførelse, boksning eller unboxing kommer derefter, og den sidste handling vil altid være varargs.

Som en underlig kendsgerning vidste du, at char type accepterer tal?

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

Hvad man skal huske om overbelastning

Overbelastning er en meget kraftfuld teknik til scenarier, hvor du har brug for det samme metodenavn med forskellige parametre. Det er en nyttig teknik, fordi det at have det rigtige navn i din kode er en stor forskel for læsbarhed. I stedet for at duplikere metoden og tilføje rod til din kode, kan du simpelthen overbelaste den. Hvis du gør dette, holder din kode ren og let at læse, og det reducerer risikoen for, at duplikatmetoder bryder en del af systemet.

Hvad man skal huske på: Ved overbelastning af en metode vil JVM gøre mindst mulig indsats; dette er rækkefølgen af ​​den lateste vej til henrettelse:

  • Først udvides
  • Andet er boksning
  • Tredje er Varargs

Hvad man skal passe på: Tricky situationer vil opstå ved at erklære et nummer direkte: 1 vil være int og 1.0 vil være dobbelt.

Husk også, at du eksplicit kan erklære disse typer ved hjælp af syntaksen 1F eller 1f for a flyde eller 1D eller 1d for en dobbelt.

Dette afslutter vores første Java Challenger, der introducerer JVM's rolle i metodeoverbelastning. Det er vigtigt at indse, at JVM iboende er doven og altid vil følge den lateste vej til henrettelse.

 

Svar nøgle

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

Mere om metodeoverbelastning i Java

  • Java 101: Klasser og objekter i Java: En ægte begynders introduktion til klasser og objekter, herunder korte sektioner om metoder og metodeoverbelastning.
  • Java 101: Elementære Java-sprogfunktioner: Lær mere om, hvorfor det betyder noget, at Java er et stærkt skrevet sprog, og få en fuld introduktion til primitive typer i Java.
  • For mange parametre i Java-metoder, del 4: Undersøg begrænsningerne og ulemperne ved metodeoverbelastning, og hvordan de kan afhjælpes ved at integrere brugerdefinerede typer og parameterobjekter.

Denne historie, "Metodeoverbelastning i JVM", blev oprindeligt udgivet af JavaWorld.