Programmering

Arv i Java, del 2: Objekt og dets metoder

Java tilbyder et standard klassebibliotek bestående af tusindvis af klasser og andre referencetyper. På trods af forskellen i deres evner udgør disse typer et massivt arvshierarki ved direkte eller indirekte at udvide Objekt klasse. Dette gælder også for alle klasser og andre referencetyper, du opretter.

Den første halvdel af denne vejledning om Java-arv viste dig de grundlæggende om arv, specifikt hvordan du bruger Java'erstrækker sig og super nøgleord for at udlede en underordnet klasse fra en overordnet klasse, påberåbe sig overordnede klassekonstruktører og -metoder, tilsidesætte metoder og mere. Nu vender vi vores fokus mod moderskibet i Java-klassens arvshierarki, java.lang.Objekt.

Studerer Objekt og dens metoder hjælper dig med at få en mere funktionel forståelse af arv og hvordan det fungerer i dine Java-programmer. At være fortrolig med disse metoder vil generelt hjælpe dig med at få mere mening over Java-programmer.

download Hent koden Download kildekoden for eksempel applikationer i denne vejledning. Oprettet af Jeff Friesen til JavaWorld.

Objekt: Java's superklasse

Objekt er rodklassen eller den ultimative superklasse af alle andre Java-klasser. Opbevaret i java.lang pakke, Objekt erklærer følgende metoder, som alle andre klasser arver:

  • beskyttet objektklon ()
  • boolske lig (Objekt obj)
  • beskyttet tomrum afsluttes ()
  • Klasse getClass ()
  • int hashCode ()
  • ugyldig meddelelse ()
  • ugyldig notifyAll ()
  • String toString ()
  • ugyldig ventetid ()
  • ugyldig ventetid (lang timeout)
  • ugyldig ventetid (lang timeout, int nanoer)

En Java-klasse arver disse metoder og kan tilsidesætte enhver metode, der ikke er deklareret endelig. For eksempel er den ikke-endeligtoString () Metoden kan tilsidesættes, mens endeligvente() metoder kan ikke.

Vi ser på hver af disse metoder, og hvordan de gør det muligt for dig at udføre specielle opgaver i forbindelse med dine Java-klasser. Lad os først overveje de grundlæggende regler og mekanismer for Objekt arv.

Generiske typer

På listen ovenfor har du måske bemærket det getClass (), hvis Klasse returtype er et eksempel på en generisk type. Jeg diskuterer generiske typer i en fremtidig artikel.

Udvidet objekt: Et eksempel

En klasse kan eksplicit udvide Objektsom vist i liste 1.

Notering 1. Eksplicit udvider objektet

offentlig klasse Medarbejder udvider objekt {privat strengnavn; offentlig ansat (strengnavn) {this.name = navn; } public String getName () {return name; } offentlig statisk ugyldig hoved (String [] args) {Medarbejder emp = ny medarbejder ("John Doe"); System.out.println (emp.getName ()); }}

Fordi du højst kan udvide en anden klasse (husk fra del 1, at Java ikke understøtter klassebaseret multipel arv), er du ikke tvunget til eksplicit at udvide Objekt; Ellers kunne du ikke udvide nogen anden klasse. Derfor vil du udvide Objekt implicit som vist i liste 2.

Notering 2. Implicit udvide objektet

offentlig klassemedarbejder {privat strengnavn; offentlig ansat (strengnavn) {this.name = navn; } public String getName () {return name; } offentlig statisk ugyldig hoved (String [] args) {Medarbejder emp = ny medarbejder ("John Doe"); System.out.println (emp.getName ()); }}

Kompilér lister 1 eller lister 2 som følger:

javac Medarbejder.java

Kør den resulterende applikation:

java Medarbejder

Du skal overholde følgende output:

John Doe

Find ud af mere om en klasse: getClass ()

Det getClass () metoden returnerer runtime-klassen for ethvert objekt, som den kaldes på. Det runtime klasse er repræsenteret af en Klasse objekt, som findes i java.lang pakke. Klasse er indgangspunktet i Java Reflection API, som du lærer om, når vi kommer ind i mere avancerede emner i Java-programmering. Indtil videre skal du vide, at et Java-program bruger Klasse og resten af ​​Java Reflection API for at lære om sin egen struktur.

Klasseobjekter og statiske synkroniserede metoder

De vendte tilbage Klasse objekt er det objekt, der er låst af statisk synkroniseret metoder til den repræsenterede klasse; for eksempel, statisk synkroniseret ugyldigt foo () {}. (Jeg introducerer Java-synkronisering i en fremtidig tutorial.)

Kopiering af objekter: klon ()

Det klon () metoden opretter og returnerer en kopi af det objekt, som det kaldes på. Fordi klon ()Returtype er Objekt, objektet henviser til det klon () returneringer skal kastes til objektets faktiske type, før henvisningen tildeles en variabel af objektets type. Listing 3 præsenterer en applikation, der demonstrerer kloning.

Liste 3. Kloning af et objekt

klasse CloneDemo implementerer Cloneable {int x; offentlig statisk ugyldig hoved (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); }}

Liste 3's CloneDemo klasse implementerer Klonabel interface, som findes i java.lang pakke. Klonabel implementeres af klassen (via redskaber nøgleord) for at forhindre Objekt's klon () metode fra at kaste en forekomst af CloneNotSupportedException klasse (findes også i java.lang).

CloneDemo erklærer en singel int-baseret instansfelt navngivet x og en hoved () metode, der udøver denne klasse. hoved () erklæres med en kaster klausul, der passerer CloneNotSupportedException op metoden opkald stakken.

hoved () første øjeblikkelige CloneDemo og initialiserer den resulterende instans kopi af x til 5. Derefter outputter instansens x værdi og opkald klon () i dette tilfælde, at kaste det returnerede objekt til CloneDemo inden du gemmer dens reference. Endelig udsender det klonens x feltværdi.

Kompilering Listing 3 (javac CloneDemo.java) og kør applikationen (java CloneDemo). Du skal overholde følgende output:

cd.x = 5 cd2.x = 5

Tilsidesættelse af klon ()

Det forrige eksempel behøvede ikke at tilsidesætte klon () fordi koden, der ringer klon () er placeret i klassen, der klones (CloneDemo). Hvis opkaldet til klon () var placeret i en anden klasse, men så skulle du tilsidesætte klon (). Fordi klon () erklæres beskyttet, ville du modtage en "klon har beskyttet adgang i Objekt"besked, hvis du ikke tilsidesatte den, før du sammensatte klassen. Listing 4 præsenterer en refactored Listing 3, der viser tilsidesættelse klon ().

Fortegnelse 4. Kloning af et objekt fra en anden klasse

klasse Data implementerer Cloneable {int x; @Override public Object-klon () kaster CloneNotSupportedException {returner 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); }}

Fortegnelse 4 erklærer en Data klasse, hvis forekomster skal klones. Data implementerer Klonabel interface for at forhindre en CloneNotSupportedException fra at blive kastet, når klon () metode kaldes. Det erklærer derefter int-baseret instansfelt xog tilsidesætter klon () metode. Det klon () metode udføres super.clone () at kalde sin superklasse (dvs. Objekt's) klon () metode. Den altoverskyggende klon () metode identificerer CloneNotSupportedException i dets kaster klausul.

Liste 4 erklærer også a CloneDemo klasse, der: instantierer Datainitialiserer sit instansfelt, output værdien af ​​instansfeltet, kloner Data objekt og udsender sin instansfeltværdi.

Kompilere lister 4 (javac CloneDemo.java) og kør applikationen (java CloneDemo). Du skal overholde følgende output:

data.x = 5 data2.x = 5

Lav kloning

Lav kloning (også kendt som lav kopiering) henviser til at duplikere et objekts felter uden at duplikere nogen objekter, der henvises til fra objektets referencefelter (hvis der er nogen referencefelter). Liste 3 og 4 viste faktisk lav kloning. Hver af de cd-, cd2-, data- og data2-henviste felter identificerer et objekt, der har sin egen kopi af int-baseret x Mark.

Lav kloning fungerer godt, når alle felter er af den primitive type, og (i mange tilfælde), når der henvises til nogen referencefelter uforanderlig (uforanderlige) objekter. Men hvis nogen refererede objekter er mutable, kan ændringer foretaget på et af disse objekter ses af det originale objekt og dets (e) klon (er). Liste 5 viser.

Fortegnelse 5. Problemet med lav kloning i en referencefeltkontekst

klasse Medarbejder implementerer Klonbar {privat strengnavn; privat int alder privat adresse adresse Medarbejder (strengnavn, alder, adresseadresse) {dette.navn = navn; this.age = alder; denne.adresse = adresse; } @ Override public Object-klon () kaster CloneNotSupportedException {returner super.clone (); } Adresse getAddress () {returadresse; } String getName () {return name; } int getAge () {return age; }} klasse Adresse {privat strengby; Adresse (strengby) {this.city = by; } String getCity () {return city; } ugyldig setCity (strengby) {this.city = by; }} klasse CloneDemo {public static void main (String [] args) kaster CloneNotSupportedException {Medarbejder e = ny medarbejder ("John Doe", 49, ny adresse ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Medarbejder e2 = (Medarbejder) 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 ()); }}

Notering 5 gaver Medarbejder, Adresseog CloneDemo klasser. Medarbejder erklærer navn, alderog adresse felter; og er klonbar. Adresse erklærer en adresse bestående af en by og dens forekomster kan ændres. CloneDemo driver applikationen.

CloneDemo's hoved () metode skaber en Medarbejder objekt og kloner dette objekt. Derefter ændres byens navn i originalen Medarbejder objekt adresse Mark. Fordi begge Medarbejder objekter refererer til det samme Adresse objekt, den ændrede by ses af begge objekter.

Kompilere oversigt 5 (javac CloneDemo.java) og kør denne applikation (java CloneDemo). Du skal overholde følgende output:

John Doe: 49: Denver John Doe: 49: Denver John Doe: 49: Chicago John Doe: 49: Chicago

Dyb kloning

Dyb kloning (også kendt som dyb kopiering) henviser til at duplikere et objekts felter, således at eventuelle refererede objekter duplikeres. Desuden duplikeres de refererede objekter fra referencede objekter og så videre. Listing 6 refactors Listing 5 for at demonstrere dyb kloning.

Fortegnelse 6. Dyb kloning af adressefeltet

klasse Medarbejder implementerer Klonbar {privat strengnavn; privat int alder privat adresse adresse Medarbejder (strengnavn, alder, adresseadresse) {dette.navn = navn; this.age = alder; denne.adresse = adresse; } @ Override public Object-klon () kaster CloneNotSupportedException {Medarbejder e = (Medarbejder) super.clone (); e.adresse = (adresse) adresse.klon (); returnere e; } Adresse getAddress () {returadresse; } String getName () {return name; } int getAge () {return age; }} klasse Adresse {privat strengby; Adresse (strengby) {this.city = by; } @ Override public Object clone () {return new Address (new String (city)); } String getCity () {return city; } ugyldig setCity (strengby) {this.city = by; }} klasse CloneDemo {offentlig statisk ugyldig hoved (String [] args) kaster CloneNotSupportedException {Medarbejder e = ny medarbejder ("John Doe", 49, ny adresse ("Denver")); System.out.println (e.getName () + ":" + e.getAge () + ":" + e.getAddress (). GetCity ()); Medarbejder e2 = (Medarbejder) 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 ()); }}

Liste 6 viser det Medarbejder's klon () metode første opkald super.clone (), som lavt kopierer navn, alderog adresse felter. Derefter kalder det klon () på den adresse felt for at lave en kopi af den refererede Adresse objekt. Adresse tilsidesætter klon () metode og afslører et par forskelle fra tidligere klasser, der tilsidesætter denne metode:

  • Adresse implementerer ikke Klonabel. Det er ikke nødvendigt, fordi kun Objekt's klon () metoden kræver, at en klasse implementerer denne grænseflade, og dette klon () metode kaldes ikke.
  • Den altoverskyggende klon () metoden kaster ikke CloneNotSupportedException. Denne undtagelse kastes kun fra Objekt's klon () metode, som ikke kaldes. Derfor behøver undtagelsen ikke at blive håndteret eller videregivet metoden-opkaldstakken via en kasteklausul.
  • Objekt's klon () metode kaldes ikke (der er ingen super.clone () opkald) fordi overfladisk kopiering ikke er påkrævet for Adresse klasse - der er kun et enkelt felt at kopiere.