Erfarne Java-utviklere tar ofte for gitt Java-funksjoner som nykommere synes er forvirrende. For eksempel kan en nybegynner være forvirret om Gjenstand
klasse. Dette innlegget lanserer en tredelt serie der jeg presenterer og svarer på spørsmål om Gjenstand
og dens metoder.
King Object
Spørsmål: Hva er Gjenstand
klasse?
EN: De Gjenstand
klasse, som er lagret i java.lang
pakke, er den ultimate superklassen for alle Java-klasser (bortsett fra Gjenstand
). Også matriser utvides Gjenstand
. Imidlertid utvides grensesnittene ikke Gjenstand
, som er påpekt i avsnitt 9.6.3.4 i Java Language Specification: ... vurdere at mens et grensesnitt ikke har Gjenstand
som en supertype ....
Gjenstand
erklærer følgende metoder, som jeg vil diskutere fullt ut senere i dette innlegget og i resten av denne serien:
beskyttet objektklon ()
boolsk er lik (Objekt obj)
beskyttet tomrom fullføre ()
Klasse getClass ()
int hashCode ()
ugyldig beskjed ()
void notifyAll ()
String toString ()
ugyldig vent ()
ugyldig ventetid (lang tidsavbrudd)
ugyldig ventetid (lang tidsavbrudd, int nanoer)
En Java-klasse arver disse metodene og kan overstyre enhver metode som ikke er deklarert endelig
. For eksempel den ikke-endelig
toString ()
metoden kan overstyres, mens endelig
vente()
metoder kan ikke overstyres.
Spørsmål: Kan jeg eksplisitt utvide Gjenstand
klasse?
EN: Ja, du kan eksplisitt utvide Gjenstand
. Sjekk for eksempel oppføring 1.
Oppføring 1. Eksplisitt utvider Gjenstand
importere java.lang.Object; offentlig klasse Ansatt utvider Objekt {privat Strengnavn; offentlig ansatt (strengnavn) {this.name = navn; } public String getName () {return name; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}
Du kan samle oppføring 1 (javac Ansatt.java
) og kjør det resulterende Ansatt.klasse
fil (java Ansatt
), og du vil observere John Doe
som utdata.
Fordi kompilatoren automatisk importerer typer fra java.lang
pakken, den importere java.lang.Object;
uttalelse er unødvendig. Dessuten tvinger Java deg ikke til å eksplisitt utvide Gjenstand
. Hvis det gjorde det, ville du ikke kunne utvide andre klasser enn Gjenstand
fordi Java begrenser klasseutvidelse til en enkelt klasse. Derfor vil du vanligvis utvide Gjenstand
implisitt, som vist i liste 2.
Oppføring 2. Implisitt utvides Gjenstand
offentlig klasse Ansatt {privat strengnavn; offentlig ansatt (strengnavn) {this.name = navn; } public String getName () {return name; } public static void main (String [] args) {Employee emp = new Employee ("John Doe"); System.out.println (emp.getName ()); }}
Som i Listing 1, Listing 2's Ansatt
klasse utvider Gjenstand
og arver metodene.
Kloning av gjenstander
Spørsmål: Hva gjør klone ()
metode oppnå?
EN: De klone ()
metoden oppretter og returnerer en kopi av objektet som denne metoden kalles for.
Spørsmål: Hvordan fungerer det klone ()
metodearbeid?
EN:Gjenstand
redskaper klone ()
som en innfødt metode, som betyr at koden er lagret i et eget bibliotek. Når denne koden kjøres, sjekker den klassen (eller en superklasse) av påkallingsobjektet for å se om den implementerer java.lang.Cloneable
grensesnitt - Gjenstand
implementerer ikke Klonbar
. Hvis dette grensesnittet ikke er implementert, klone ()
kaster java.lang.CloneNotSupportedException
, som er et avkrysset unntak (det må håndteres eller sendes opp metode-anropsstakken ved å legge til en kaste-ledd i overskriften til metoden der klone ()
ble påberopt). Hvis dette grensesnittet er implementert, klone ()
tildeler et nytt objekt og kopierer det anropende objektets feltverdier til det nye objektets ekvivalente felt, og returnerer en referanse til det nye objektet.
Spørsmål: Hvordan påberoper jeg meg klone ()
metode for å klone et objekt?
EN: Gitt en objektreferanse, påkalle klone ()
på denne referansen og kast det returnerte objektet fra Gjenstand
til typen gjenstand som klones. Listing 3 presenterer et eksempel.
Oppføring 3. Kloning av et objekt
offentlig klasse CloneDemo implementerer Cloneable {int x; public static void main (String [] args) kaster CloneNotSupportedException {CloneDemo cd = new CloneDemo (); cd.x = 5; System.out.printf ("cd.x =% d% n", cd.x); CloneDemo cd2 = (CloneDemo) cd.clone (); System.out.printf ("cd2.x =% d% n", cd2.x); }}
Oppføring 3 erklærer a CloneDemo
klasse som implementerer Klonbar
grensesnitt. Dette grensesnittet må implementeres eller påkalles av Gjenstand
s klone ()
metoden vil resultere i et kast CloneNotSupportedException
forekomst.
CloneDemo
erklærer en singel int
-basert forekomstfelt navngitt x
og en hoved()
metode som utøver denne klassen. hoved()
blir erklært med en kasteklausul som går CloneNotSupportedException
opp metoden-samtalestakken.
hoved()
første øyeblikkelig CloneDemo
og initialiserer den resulterende forekomstens kopi av x
til 5
. Den sender deretter forekomsten ut x
verdi og påkaller klone ()
i dette tilfellet å kaste det returnerte objektet til CloneDemo
før du lagrer referansen. Til slutt gir den ut klonens x
feltverdi.
Kompilere oppføring 3 (javac CloneDemo.java
) og kjør applikasjonen (java CloneDemo
). Du bør følge følgende utdata:
cd.x = 5 cd2.x = 5
Spørsmål: Hvorfor trenger jeg å overstyre klone ()
metode?
EN: Det forrige eksemplet trengte ikke å overstyre klone ()
metode fordi koden som påberoper klone ()
ligger i klassen som klones (dvs. CloneDemo
klasse). Imidlertid, hvis klone ()
påkallingen ligger i en annen klasse, må du overstyre klone ()
. Ellers vil du motta en "klon har beskyttet tilgang i Object
"melding fordi klone ()
blir erklært beskyttet
. Listing 4 presenterer en refactored Listing 3 for å demonstrere overstyring klone ()
.
Oppføring 4. Kloning av et objekt fra en annen klasse
klasse Data implementerer Cloneable {int x; @ Override public Object-klon () kaster CloneNotSupportedException {return super.clone (); }} public class CloneDemo {public static void main (String [] args) kaster CloneNotSupportedException {Data data = new Data (); data.x = 5; System.out.printf ("data.x =% d% n", data.x); Data data2 = (Data) data.clone (); System.out.printf ("data2.x =% d% n", data2.x); }}
Oppføring 4 erklærer a Data
klasse hvis forekomster skal klones. Denne klassen implementerer Klonbar
grensesnitt for å forhindre CloneNotSupportedException
fra å bli kastet når klone ()
metoden kalles, erklærer int
-basert forekomstfelt x
, og overstyrer klone ()
metode. Denne metoden kjøres super.clone ()
å påkalle sin superklasse (Gjenstand
i dette eksemplet) klone ()
metode. Det overordnede klone ()
metoden identifiserer CloneNotSupportedException
i kasteklausulen.
Oppføring 4 erklærer også a CloneDemo
klasse som instantierer Data
, initialiserer instansfeltet, sender ut verdien av denne forekomstens forekomstfelt, kloner Data
forekomst, og sender ut denne forekomstens forekomstfeltverdi.
Kompilere oppføring 4 (javac CloneDemo.java
) og kjør applikasjonen (java CloneDemo
). Du bør følge følgende utdata:
data.x = 5 data2.x = 5
Spørsmål: Hva er grunne kloning?
EN:Grunn kloning (også kjent som grunne kopiering) er duplisering av et objekts felt uten å duplisere objekter som det refereres til fra objektets referansefelt (hvis det har noen). Listing 3 og 4 viser grunne kloning. Hver av cd
-, cd2
-, data
-, og data2
-henviste felt identifiserer et objekt som har sin egen kopi av int
-basert x
felt.
Grunn kloning fungerer bra når alle felt er av primitiv type og (i mange tilfeller) når noen referansefelt refererer til uforanderlig (uforanderlige) gjenstander. Imidlertid, hvis noen refererte objekter er mutable, kan endringer som er gjort på et av disse objektene sees av det opprinnelige objektet og dets klon (er). Oppføring 5 presenterer en demonstrasjon.
Oppføring 5. Demonstrere problemet med grunne kloning i en referansefeltkontekst
klasse Ansatt implementerer Cloneable {private String name; privat alder; privat adresse adresse; Ansatt (strengnavn, alder, adresseadresse) {this.name = navn; this.age = alder; denne.adressen = adresse; } @Override public Object clone () kaster CloneNotSupportedException {return super.clone (); } Adresse getAddress () {returadresse; } String getName () {return name; } int getAge () {retur alder; }} klasse Adresse {privat strengby; Adresse (strengby) {this.city = by; } String getCity () {retur by; } ugyldig setCity (strengby) {this.city = by; }} offentlig klasse CloneDemo {offentlig statisk ugyldig hoved (String [] args) kaster CloneNotSupportedException {ansatt e = ny ansatt ("John Doe", 49, ny adresse ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Ansatt e2 = (Ansatt) e.clone (); System.out.printf ("% s:% d:% s% n", e2.getName (), e2.getAge (), e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); System.out.printf ("% s:% d:% s% n", e2.getName (), e2.getAge (), e2.getAddress (). GetCity ()); }}
Oppføring 5 gaver Ansatt
, Adresse
, og CloneDemo
klasser. Ansatt
erklærer Navn
, alder
, og adresse
Enger; og er klonbar. Adresse
erklærer en adresse som består av en by og dens forekomster er foranderlige. CloneDemo
driver applikasjonen.
CloneDemo
s hoved()
metoden skaper en Ansatt
objekt og kloner dette objektet. Det endrer deretter byens navn i originalen Ansatt
objektets adresse
felt. Fordi begge deler Ansatt
objekter refererer til det samme Adresse
objekt, blir den forandrede byen sett av begge objektene.
Kompilere oppføring 5 (javac CloneDemo.java
) og kjør dette programmet (java CloneDemo
). Du bør følge følgende utdata:
John Doe: 49: Denver John Doe: 49: Denver John Doe: 49: Chicago John Doe: 49: Chicago
Spørsmål: Hva er dyp kloning?
EN:Dyp kloning (også kjent som dyp kopiering) er duplisering av et objekts felt slik at eventuelle refererte objekter dupliseres. Videre dupliseres deres refererte objekter - og så videre. For eksempel, Listing 6 refactors Listing 5 for å utnytte dyp kloning. Det demonstrerer også kovariante returtyper og en mer fleksibel måte å klone på.
Oppføring 6. Dypt kloning av adresse
felt
klasse Ansatt implementerer Cloneable {private String name; privat alder; privat adresse adresse; Ansatt (strengnavn, alder, adresseadresse) {this.name = navn; this.age = alder; denne.adressen = adresse; } @ Override public Employee clone () kaster CloneNotSupportedException {Employee e = (Employee) super.clone (); e.adresse = adresse.klon (); returnere e; } Adresse getAddress () {returadresse; } String getName () {return name; } int getAge () {retur alder; }} klasse Adresse {privat strengby; Adresse (strengby) {this.city = by; } @ Override public Address clone () {return new Address (new String (city)); } String getCity () {retur by; } ugyldig setCity (strengby) {this.city = by; }} offentlig klasse CloneDemo {offentlig statisk ugyldig hoved (String [] args) kaster CloneNotSupportedException {ansatt e = ny ansatt ("John Doe", 49, ny adresse ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Ansatt e2 = (Ansatt) e.clone (); System.out.printf ("% s:% d:% s% n", e2.getName (), e2.getAge (), e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); System.out.printf ("% s:% d:% s% n", e2.getName (), e2.getAge (), e2.getAddress (). GetCity ()); }}
Oppføring 6 utnytter Java's støtte for kovariante returtyper for å endre returtypen av Ansatt
er overordnet klone ()
metode fra Gjenstand
til Ansatt
. Fordelen er at koden utenfor Ansatt
kan klone en Ansatt
objekt uten å måtte kaste dette objektet til Ansatt
type.
Ansatt
s klone ()
metoden påberoper seg først super.clone ()
, som grunt kopierer Navn
, alder
, og adresse
Enger. Den påberoper seg deretter klone ()
på adresse
felt for å lage en duplikat av den refererte Adresse
gjenstand.
De Adresse
klasse overstyrer klone ()
metode og avslører noen forskjeller fra tidligere klasser som overstyrer denne metoden:
Adresse
implementerer ikkeKlonbar
. Det er ikke nødvendig fordi bareGjenstand
sklone ()
metoden krever at en klasse implementerer dette grensesnittet, og detteklone ()
metoden blir ikke kalt.- Det overordnede
klone ()
metoden kaster ikkeCloneNotSupportedException
. Dette avmerkede unntaket kastes bare fraGjenstand
sklone ()
metoden, som ikke kalles. Derfor trenger ikke unntaket å håndteres eller sendes opp metoden-samtalestakken via en kast-klausul. Gjenstand
sklone ()
metoden kalles ikke (det er ingensuper.clone ()
kall) fordi grunne kopiering ikke er påkrevd forAdresse
klasse - det er bare et enkelt felt å kopiere.
Å klone Adresse
objekt, er det tilstrekkelig å lage et nytt Adresse
objektet og initialiser det til et duplikat av objektet det refereres til fra by
felt. Den nye Adresse
gjenstand returneres deretter.