Inkluderer en metodes signatur returtypen i Java?

1. Oversigt

Metodesignaturen er kun en delmængde af hele metodedefinitionen i Java. Således kan den nøjagtige anatomi af signaturen forårsage forvirring.

I denne vejledning lærer vi elementerne i metodesignaturen og dens implikationer i Java-programmering.

2. Metodesignatur

Metoder i Java understøtter overbelastning, hvilket betyder at flere metoder med samme navn kan defineres i samme klasse eller klassehierarki. Derfor skal compileren være i stand til statisk at binde den metode, klientkoden refererer til. Af denne grund er metoden signatur identificerer entydigt hver metode.

Ifølge Oracle er metoden signatur består af navn og parametertyper. Derfor er alle de andre elementer i metodens erklæring, såsom modifikatorer, returtype, parameternavne, undtagelsesliste og brødtekst ikke en del af signaturen.

Lad os se nærmere på metodeoverbelastning og hvordan det relaterer til metodesignaturer.

3. Overbelastningsfejl

Lad os overveje følgende kode:

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

Som vi kan se, kompileres koden, da metoderne har forskellige lister over parametertyper. I virkeligheden kan compileren deterministisk binde ethvert opkald til det ene eller det andet.

Lad os nu teste, om det er lovligt at overbelaste ved at tilføje følgende metode:

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

Når vi kompilerer, får vi en “metode er allerede defineret i klasse” -fejl. Det beviser metoden returtype er ikke en del af metodesignaturen.

Lad os prøve det samme med modifikatorer:

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

Vi ser stadig den samme "metode er allerede defineret i klasse" -fejl. Derfor er metoden signatur er ikke afhængig af modifikatorer.

Overbelastning ved at ændre kastede undtagelser kan testes ved at tilføje:

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

Igen ser vi fejlen "metoden er allerede defineret i klassen", hvilket indikerer kastedeklaration kan ikke være en del af signaturen.

Den sidste ting, vi kan teste, er, om ændring af parameternavne tillader overbelastning. Lad os tilføje følgende metode:

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

Som forventet får vi den samme kompileringsfejl. Det betyder at parameternavne påvirker ikke metodesignaturen.

3. Generiske gener og type sletning

Med generiske parametre, type sletning ændrer den effektive signatur. I virkeligheden kan det forårsage en kollision med en anden metode, der bruger den øvre grænse af den generiske type i stedet for det generiske token.

Lad os overveje 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)"); }}

Selvom signaturerne ser anderledes ud, kan kompilatoren ikke binde den korrekte metode statisk efter sletning af typen.

Vi kan se compileren erstatte T med den øvre grænse, Serialiserbar, på grund af sletning af typen. Således kolliderer den med metoden, der eksplicit anvendes Serialiserbar.

Vi ville se det samme resultat med basistypen Objekt når den generiske type ikke er bundet.

4. Parameterlister og polymorfisme

Metodesignaturen tager højde for de nøjagtige typer. Det betyder, at vi kan overbelaste en metode, hvis parametertype er en underklasse eller superklasse.

Vi skal dog være særligt opmærksomme som statisk binding vil forsøge at matche ved hjælp af polymorfisme, auto-boksning og typekampagne.

Lad os se på følgende kode:

public Number sum (Integer term1, Integer term2) {System.out.println ("Tilføjelse af heltal"); returperiode1 + term2; } offentligt tal (antal term1, antal ord2) {System.out.println ("Tilføjelse af numre"); return term1.doubleValue () + term2.doubleValue (); } public Number sum (Object term1, Object term2) {System.out.println ("Tilføjelse af objekter"); returterm1.hashCode () + term2.hashCode (); }

Koden ovenfor er fuldstændig lovlig og kompileres. Forvirring kan opstå, når vi kalder disse metoder, da vi ikke kun har brug for at vide den nøjagtige metodesignatur, vi kalder, men også hvordan Java statisk binder baseret på de faktiske værdier.

Lad os undersøge et par metodeopkald, der ender med at være bundet til sum (Heltal, Heltal):

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

For det første opkald har vi de nøjagtige parametertyper Heltal, Heltal. Ved det andet opkald bokser Java automatisk int til Heltal for os. Endelig transformerer Java byteværdien 0x1 til int ved hjælp af type forfremmelse og derefter automatisk afkasse den til Heltal.

På samme måde har vi følgende opkald, der binder til sum (antal, antal):

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

Ved det første opkald har vi det dobbelt værdier, der automatisk bokses til Dobbelt. Og så ved hjælp af polymorfisme, Dobbelt Tændstikker Nummer. Identisk, Flyde Tændstikker Nummer til det andet opkald.

Lad os observere det faktum, at begge Flyde og Dobbelt arve fra Nummer og Objekt. Standardbindingen er dog til Nummer. Dette skyldes, at Java automatisk matcher til de nærmeste supertyper, der matcher en metodesignatur.

Lad os nu overveje følgende metodeopkald:

obj.sum (2, "John");

I dette eksempel har vi en int til Heltal automatisk afkrydsningsfelt for den første parameter. Der er dog ingen sum (heltal, streng) overbelastning for dette metodenavn. Som følge heraf vil Java køre igennem alle parametrene supertyper, der skal kastes fra nærmeste forælder til Objekt indtil den finder en match. I dette tilfælde binder det sig til sum (Objekt, Objekt).

For at ændre standardbindingen kan vi bruge eksplicit parameter casting som følger:

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

5. Vararg-parametre

Lad os nu vende vores opmærksomhed mod hvordan varargs påvirke metodens effektive signatur og statisk binding.

Her har vi en overbelastet metode ved hjælp af varargs:

public Number sum (Object term1, Object term2) {System.out.println ("Tilføjelse af objekter"); returterm1.hashCode () + term2.hashCode (); } public Number sum (Object term1, Object ... term2) {System.out.println ("Tilføjelse af variable argumenter:" + term2.length); int resultat = term1.hashCode (); for (Objekt o: term2) {resultat + = o.hashCode (); } returnere resultat }

Så hvad er metodernes effektive underskrifter? Det har vi allerede set sum (Objekt, Objekt) er underskriften for den første. Variable argumenter er i det væsentlige arrays, så den effektive signatur for den anden efter kompilering er sum (Objekt, Objekt []).

Et vanskeligt spørgsmål er, hvordan kan vi vælge den bindende metode, når vi kun har to parametre?

Lad os overveje følgende opkald:

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

Det første opkald vil naturligvis binde sig til sum (Objekt, Objekt) og den anden til sum (Objekt, Objekt []). For at tvinge Java til at kalde den anden metode med to objekter, skal vi pakke den ind i et array som i det tredje opkald.

Den sidste ting at bemærke her er, at erklæring om følgende metode kolliderer med vararg-versionen:

offentligt tal (Objekttermin1, Objekt [] term2) {// ...}

6. Konklusion

I denne vejledning lærte vi, at metodesignaturerne består af navnet og listen over parametertyper. Modifikatorerne, returtypen, parameternavne og undtagelseslisten kan ikke skelne mellem overbelastede metoder og er således ikke en del af signaturen.

Vi har også set på, hvordan type sletning og varargs skjuler den effektive metodesignatur, og hvordan vi kan tilsidesætte Java's statiske metodebinding.

Som sædvanligt er alle kodeeksempler vist i denne artikel tilgængelige på GitHub.


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