Inkluderer en metodes signatur returtype i Java?

1. Oversikt

Metodesignaturen er bare et delsett av hele metodedefinisjonen i Java. Dermed kan den eksakte anatomien til signaturen forårsake forvirring.

I denne opplæringen lærer vi elementene i metodesignaturen og dens implikasjoner i Java-programmering.

2. Metodesignatur

Metoder i Java støtter overbelastning, noe som betyr at flere metoder med samme navn kan defineres i samme klasse eller klassehierarki. Derfor må kompilatoren kunne statisk binde metoden klientkoden refererer til. Av denne grunn, metoden signatur identifiserer hver metode unikt.

I følge Oracle, metoden signatur består av navn og parametertyper. Derfor er ikke alle de andre elementene i metodens erklæring, som modifikatorer, returtype, parameternavn, unntaksliste og brødtekst, en del av signaturen.

La oss se nærmere på overbelastning av metoden og hvordan den forholder seg til metodesignaturer.

3. Overbelastningsfeil

La oss vurdere følgende kode:

public void print () {System.out.println ("Signatur er: print ()"); } public void print (int parameter) {System.out.println ("Signatur er: print (int)"); }

Som vi kan se, kompileres koden ettersom metodene har forskjellige parametertypelister. I virkeligheten kan kompilatoren deterministisk binde ethvert anrop til det ene eller det andre.

La oss nå teste om det er lovlig å overbelaste ved å legge til følgende metode:

public int print () {System.out.println ("Signatur er: print ()"); retur 0; }

Når vi kompilerer, får vi feilen “metoden er allerede definert i klassen”. Det beviser metoden returtype er ikke en del av metodesignaturen.

La oss prøve det samme med modifikatorer:

privat endelig ugyldig utskrift () {System.out.println ("Signatur er: utskrift ()"); }

Vi ser fortsatt den samme feilen "metoden er allerede definert i klassen". Derfor er metoden signatur er ikke avhengig av modifikatorer.

Overbelastning ved å endre kastede unntak kan testes ved å legge til:

public void print () kaster IllegalStateException {System.out.println ("Signatur er: print ()"); kaste nye IllegalStateException (); }

Igjen ser vi feilen "metoden er allerede definert i klassen", noe som indikerer kastedeklarasjon kan ikke være en del av signaturen.

Det siste vi kan teste er om endring av parameternavn tillater overbelastning. La oss legge til følgende metode:

offentlig tomtrykk (int anotherParameter) {System.out.println ("Signatur er: print (int)"); }

Som forventet får vi den samme kompileringsfeilen. Dette betyr at parameternavn påvirker ikke metodesignaturen.

3. Generics og Type Erasure

Med generiske parametere, type sletting endrer den effektive signaturen. I virkeligheten kan det føre til en kollisjon med en annen metode som bruker øvre grense av generisk type i stedet for generisk token.

La oss vurdere følgende kode:

public class OverloadingErrors {public void printElement (T t) {System.out.println ("Signatur er: printElement (T)"); } public void printElement (Serializable o) {System.out.println ("Signatur er: printElement (Serializable)"); }}

Selv om signaturene ser annerledes ut, kan ikke kompilatoren statisk binde den riktige metoden etter typeslette.

Vi kan se kompilatoren erstatte T med øvre grense, Serialiserbar, på grunn av type sletting. Dermed kolliderer den med metoden som eksplisitt brukes Serialiserbar.

Vi ville se det samme resultatet med basistypen Gjenstand når den generiske typen ikke har noen bånd.

4. Parameterlister og polymorfisme

Metodesignaturen tar hensyn til de eksakte typene. Det betyr at vi kan overbelaste en metode hvis parametertype er en underklasse eller superklasse.

Vi må imidlertid være spesielt oppmerksomme som statisk binding vil forsøke å matche ved hjelp av polymorfisme, autoboksing og typekampanje.

La oss ta en titt på følgende kode:

public Number sum (Integer term1, Integer term2) {System.out.println ("Legge til heltall"); returperiode1 + termin2; } offentlig nummersum (tallterm1, nummerterm2) {System.out.println ("Legge til tall"); retur term1.doubleValue () + term2.doubleValue (); } public Number sum (Object term1, Object term2) {System.out.println ("Legge til objekter"); retur term1.hashCode () + term2.hashCode (); }

Koden ovenfor er helt lovlig og vil kompilere. Det kan oppstå forvirring når du ringer til disse metodene, ettersom vi ikke bare trenger å vite den nøyaktige metodesignaturen vi ringer, men også hvordan Java statisk binder seg basert på de faktiske verdiene.

La oss utforske noen få metodesamtaler som ender opp med sum (Integer, Integer):

StaticBinding obj = new StaticBinding (); obj.sum (Integer.valueOf (2), Integer.valueOf (3)); obj.sum (2, 3); obj.sum (2, 0x1);

For den første samtalen har vi de nøyaktige parametertypene Heltall, Heltall. Ved den andre samtalen vil Java automatisk boks int til Heltall for oss. Til slutt vil Java transformere byteverdien 0x1 til int ved hjelp av type promotering og deretter automatisk boks den til Heltall.

På samme måte har vi følgende samtaler som binder seg til sum (Number, Number):

obj.sum (2.0d, 3.0d); obj.sum (Float.valueOf (2), Float.valueOf (3));

På den første samtalen har vi det dobbelt verdier som automatisk bokses til Dobbelt. Og så, ved hjelp av polymorfisme, Dobbelt fyrstikker Nummer. Identisk, Flyte fyrstikker Nummer for den andre samtalen.

La oss observere det faktum at begge Flyte og Dobbelt arve fra Nummer og Gjenstand. Standardbindingen er imidlertid til Nummer. Dette skyldes at Java automatisk samsvarer med nærmeste supertyper som samsvarer med en metodesignatur.

La oss nå vurdere følgende metodeanrop:

obj.sum (2, "John");

I dette eksemplet har vi en int til Heltall automatisk boks for den første parameteren. Det er imidlertid ingen sum (Heltall, streng) overbelastning for dette metodenavnet. Følgelig vil Java løpe gjennom alle parametere super-typene som skal kastes fra nærmeste foreldre til Gjenstand til den finner en kamp. I dette tilfellet binder det seg til sum (Objekt, Objekt).

For å endre standardbindingen kan vi bruke eksplisitt parameterskjæring som følger:

obj.sum ((Object) 2, (Object) 3); obj.sum ((Number) 2, (Number) 3);

5. Vararg-parametere

La oss nå rette oppmerksomheten mot hvordan varargs påvirke metodens effektive signatur og statisk binding.

Her har vi en overbelastet metode ved hjelp av varargs:

public Number sum (Object term1, Object term2) {System.out.println ("Legge til objekter"); retur term1.hashCode () + term2.hashCode (); } public Number sum (Object term1, Object ... term2) {System.out.println ("Legge til variable argumenter:" + term2.length); int resultat = term1.hashCode (); for (Objekt o: term2) {resultat + = o.hashCode (); } returnere resultat; }

Så hva er de effektive signaturene til metodene? Vi har allerede sett det sum (Objekt, Objekt) er signaturen for den første. Variable argumenter er egentlig matriser, så den effektive signaturen for den andre etter kompilering er sum (Objekt, Objekt []).

Et vanskelig spørsmål er hvordan vi kan velge metoden bindende når vi bare har to parametere?

La oss vurdere følgende samtaler:

obj.sum (nytt objekt (), nytt objekt ()); obj.sum (nytt Objekt (), nytt Objekt (), nytt Objekt ()); obj.sum (nytt objekt (), nytt objekt [] {nytt objekt ()});

Åpenbart vil den første samtalen binde seg til sum (Objekt, Objekt) og den andre til sum (Objekt, Objekt []). For å tvinge Java til å ringe den andre metoden med to objekter, må vi pakke den inn i en matrise som i den tredje samtalen.

Den siste tingen å merke seg her er at å erklære følgende metode vil kollidere med vararg-versjonen:

offentlig tallsum (Objektbegrep1, Objekt [] term2) {// ...}

6. Konklusjon

I denne opplæringen lærte vi at metodesignaturene består av navnet og listen over parametertyper. Modifikatorene, returtypen, parameternavnet og unntakslisten kan ikke skille mellom overbelastede metoder og er dermed ikke en del av signaturen.

Vi har også sett på hvordan type sletting og varargs skjuler den effektive metodesignaturen og hvordan vi kan overstyre Java's statiske metodebinding.

Som vanlig er alle kodeeksemplene vist i denne artikkelen tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found