Programmering

Den ultimate superklassen, del 1

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-endeligtoString () metoden kan overstyres, mens endeligvente() 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 Gjenstands 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 (Gjenstandi 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.

CloneDemos 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 Ansatter 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.

Ansatts klone () metoden påberoper seg først super.clone (), som grunt kopierer Navn, alder, og adresse Enger. Den påberoper seg deretter klone ()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 ikke Klonbar. Det er ikke nødvendig fordi bare Gjenstands klone () metoden krever at en klasse implementerer dette grensesnittet, og dette klone () metoden blir ikke kalt.
  • Det overordnede klone () metoden kaster ikke CloneNotSupportedException. Dette avmerkede unntaket kastes bare fra Gjenstands klone () metoden, som ikke kalles. Derfor trenger ikke unntaket å håndteres eller sendes opp metoden-samtalestakken via en kast-klausul.
  • Gjenstands klone () metoden kalles ikke (det er ingen super.clone () kall) fordi grunne kopiering ikke er påkrevd for Adresse 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.

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