Java tilbyr et standard klassebibliotek bestående av tusenvis av klasser og andre referansetyper. Til tross for ulikheten i deres evner, utgjør disse typene ett massivt arvshierarki ved direkte eller indirekte å utvide Gjenstand
klasse. Dette gjelder også for alle klasser og andre referansetyper du oppretter.
Første halvdel av denne veiledningen om Java-arv viste deg det grunnleggende om arv, spesielt hvordan du bruker Java-erstrekker
og super
nøkkelord for å utlede en underordnet klasse fra en overordnet klasse, påkalle foreldreklassekonstruktører og -metoder, overstyre metoder og mer. Nå vil vi rette fokus mot morsskipet til Java-klassens arvshierarki, java.lang.Objekt
.
Studerer Gjenstand
og dens metoder vil hjelpe deg med å få en mer funksjonell forståelse av arv og hvordan det fungerer i Java-programmene dine. Å være kjent med disse metodene vil hjelpe deg med å få større mening med Java-programmer, generelt.
Objekt: Java sin superklasse
Gjenstand
er rotklassen, eller den ultimate superklassen, til alle andre Java-klasser. Lagret i java.lang
pakke, Gjenstand
erklærer følgende metoder, som alle andre klasser arver:
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.
Vi ser på hver av disse metodene og hvordan de gjør det mulig for deg å utføre spesielle oppgaver i sammenheng med Java-klassene dine. La oss først vurdere grunnleggende regler og mekanismer for Gjenstand
arv.
Generiske typer
I listen ovenfor har du kanskje lagt merke til det getClass ()
, hvem sin Klasse
returtype er et eksempel på en generisk type. Jeg vil diskutere generiske typer i en fremtidig artikkel.
Extending Object: Et eksempel
En klasse kan eksplisitt utvides Gjenstand
, som vist i Listing 1.
Oppføring 1. Eksplisitt utvidende objekt
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 ()); }}
Fordi du maksimalt kan utvide en annen klasse (husk fra del 1 at Java ikke støtter klassebasert flerarv), blir du ikke tvunget til å eksplisitt utvide Gjenstand
; Ellers kunne du ikke utvide noen annen klasse. Derfor vil du utvide Gjenstand
implisitt, som vist i liste 2.
Oppføring 2. Implisitt utvider objektet
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 ()); }}
Kompiler liste 1 eller liste 2 som følger:
javac Ansatt.java
Kjør den resulterende applikasjonen:
java Ansatt
Du bør følge følgende utdata:
John Doe
Finn ut om en klasse: getClass ()
De getClass ()
metoden returnerer kjøretidsklassen til ethvert objekt den kalles på. De kjøretidsklasse er representert av en Klasse
gjenstand, som finnes i java.lang
pakke. Klasse
er inngangspunktet til Java Reflection API, som du lærer om når vi kommer inn på mer avanserte emner innen Java-programmering. For nå, vet at et Java-program bruker Klasse
og resten av Java Reflection API for å lære om sin egen struktur.
Klasseobjekter og statiske synkroniserte metoder
De returnerte Klasse
objekt er objektet som er låst av statisk synkronisert
metoder for den representerte klassen; for eksempel, statisk synkronisert ugyldig foo () {}
. (Jeg introduserer Java-synkronisering i en fremtidig opplæring.)
Dupliserende objekter: klone ()
De klone ()
metoden oppretter og returnerer en kopi av objektet som det heter. Fordi klone ()
Returtype er Gjenstand
, objektet refererer til det klone ()
returneringer må kastes til objektets faktiske type før referansen tildeles en variabel av objektets type. Listing 3 presenterer et program som demonstrerer kloning.
Oppføring 3. Kloning av et objekt
klasse CloneDemo implementerer Cloneable {int x; public static void main (String [] args) kaster CloneNotSupportedException {CloneDemo cd = new CloneDemo (); cd.x = 5; System.out.println ("cd.x =" + cd.x); CloneDemo cd2 = (CloneDemo) cd.clone (); System.out.println ("cd2.x =" + cd2.x); }}
Listing 3's CloneDemo
klasse implementerer Klonbar
grensesnitt, som finnes i java.lang
pakke. Klonbar
er implementert av klassen (via redskaper
nøkkelord) for å forhindre Gjenstand
s klone ()
metoden fra å kaste en forekomst av CloneNotSupportedException
klasse (også funnet i java.lang
).
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 kaster
klausul som passerer 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 samtaler 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
Overstyrende klon ()
Det forrige eksemplet trengte ikke å overstyre klone ()
fordi koden som ringer klone ()
ligger i klassen som klones (CloneDemo
). Hvis samtalen til klone ()
var plassert i en annen klasse, men da må du overstyre klone ()
. Fordi klone ()
blir erklært beskyttet
, vil du motta en "klon har beskyttet tilgang i Object"melding hvis du ikke overstyrte den før du kompilerte klassen. Oppføring 4 presenterer en refaktorert oppføring 3 som viser 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 (); }} klasse CloneDemo {public static void main (String [] args) kaster CloneNotSupportedException {Data data = new Data (); data.x = 5; System.out.println ("data.x =" + data.x); Data data2 = (Data) data.clone (); System.out.println ("data2.x =" + data2.x); }}
Oppføring 4 erklærer a Data
klasse hvis forekomster skal klones. Data
implementerer Klonbar
grensesnitt for å forhindre a CloneNotSupportedException
fra å bli kastet når klone ()
metoden kalles. Det erklærer da int
-basert forekomstfelt x
, og overstyrer klone ()
metode. De klone ()
metoden kjøres super.clone ()
å kalle superklassen sin (det vil si Gjenstand
's) klone ()
metode. Det overordnede klone ()
metoden identifiserer CloneNotSupportedException
i sin kaster
klausul.
Oppføring 4 erklærer også a CloneDemo
klasse som: instantiates Data
, initialiserer forekomstfeltet, sender ut verdien av forekomsten, kloner Data
objektet, og sender ut sin 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
Grunn kloning
Grunn kloning (også kjent som grunne kopiering) refererer til å duplisere et objekts felt uten å duplisere objekter som det refereres til fra objektets referansefelt (hvis det er noen referansefelt). Listing 3 og 4 demonstrerte faktisk 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 viser.
Oppføring 5. 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; }} klasse CloneDemo {public static void main (String [] args) kaster CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, new Address ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Ansatt e2 = (Ansatt) e.clone (); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); System.out.println (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
Dyp kloning
Dyp kloning (også kjent som dyp kopiering) refererer til å duplisere et objekts felt slik at eventuelle refererte objekter dupliseres. Videre dupliseres de refererte objektene til refererte objekter, og så videre. Listing 6 refactors Listing 5 for å demonstrere dyp kloning.
Oppføring 6. Dyp kloning av adressefeltet
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-klon () kaster CloneNotSupportedException {ansatt e = (ansatt) super.clone (); e.adresse = (Adresse) adresse.klone (); returnere e; } Adresse getAddress () {returadresse; } String getName () {return name; } int getAge () {retur alder; }} klasse Adresse {privat strengby; Adresse (strengby) {this.city = by; } @ Override public Object clone () {return new Address (new String (city)); } String getCity () {retur by; } ugyldig setCity (strengby) {this.city = by; }} klasse CloneDemo {public static void main (String [] args) kaster CloneNotSupportedException {Employee e = new Employee ("John Doe", 49, new Address ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Ansatt e2 = (Ansatt) e.clone (); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); e.getAddress (). setCity ("Chicago"); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); System.out.println (e2.getName () + ":" + e2.getAge () + ":" + e2.getAddress (). GetCity ()); }}
Oppføring 6 viser at Ansatt
s klone ()
metoden første samtaler super.clone ()
, som grunt kopierer Navn
, alder
, og adresse
Enger. Det kaller da klone ()
på adresse
felt for å lage en duplikat av den refererte Adresse
gjenstand. Adresse
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 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.