Erfarne Java-udviklere tager ofte for givet Java-funktioner, som nybegyndere finder forvirrende. For eksempel kan en nybegynder være forvirret over Objekt
klasse. Dette indlæg lancerer en tredelt serie, hvor jeg præsenterer og besvarer spørgsmål om Objekt
og dens metoder.
King Object
Spørgsmål: Hvad er Objekt
klasse?
EN: Det Objekt
klasse, der er gemt i java.lang
pakke, er den ultimative superklasse for alle Java-klasser (undtagen Objekt
). Arrays strækker sig også Objekt
. Grænseflader udvides dog ikke Objekt
, som er påpeget i afsnit 9.6.3.4 i Java Language Specification: ... overvej det, mens en grænseflade ikke har Objekt
som en supertype ....
Objekt
erklærer følgende metoder, som jeg vil diskutere fuldt ud senere i dette indlæg og i resten af denne serie:
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-endelig
toString ()
Metoden kan tilsidesættes, mens endelig
vente()
metoder kan ikke tilsidesættes.
Spørgsmål: Kan jeg eksplicit udvide Objekt
klasse?
EN: Ja, du kan eksplicit udvide Objekt
. Se f.eks. Listing 1.
Notering 1. Eksplicit udvides Objekt
import java.lang.Object; 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 ()); }}
Du kan sammensætte liste 1 (javac Medarbejder.java
) og kør det resulterende Medarbejderklasse
fil (java Medarbejder
), og du vil observere John Doe
som output.
Fordi kompilatoren automatisk importerer typer fra java.lang
pakke, den import java.lang.Object;
Erklæring er unødvendig. Java tvinger dig heller ikke til eksplicit at udvide Objekt
. Hvis det gjorde det, ville du ikke være i stand til at udvide andre klasser end Objekt
fordi Java begrænser klasseudvidelse til en enkelt klasse. Derfor vil du typisk udvide Objekt
implicit som vist i liste 2.
Notering 2. Implicit udvides Objekt
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 ()); }}
Som i Listing 1, Listing 2's Medarbejder
klasse udvides Objekt
og arver dens metoder.
Kloning af genstande
Spørgsmål: Hvad gør det klon ()
metode udrette?
EN: Det klon ()
metoden opretter og returnerer en kopi af det objekt, som denne metode kaldes på.
Spørgsmål: Hvordan fungerer det klon ()
metode arbejde?
EN:Objekt
redskaber klon ()
som en indfødt metode, hvilket betyder, at dens kode er gemt i et oprindeligt bibliotek. Når denne kode udføres, kontrollerer den klassen (eller en superklasse) af det påkaldende objekt for at se, om den implementerer java.lang.Cloneable
grænseflade - Objekt
implementerer ikke Klonabel
. Hvis denne grænseflade ikke er implementeret, klon ()
kaster java.lang.CloneNotSupportedException
, som er en afkrydset undtagelse (den skal håndteres eller videresendes til metodeopkaldsstakken ved at tilføje et kasteklausul til overskriften på den metode, klon ()
blev påberåbt). Hvis denne grænseflade er implementeret, klon ()
tildeler et nyt objekt og kopierer det kaldende objekts feltværdier til det nye objekts ækvivalente felter og returnerer en reference til det nye objekt.
Spørgsmål: Hvordan påberåber jeg mig klon ()
metode til at klone et objekt?
EN: Givet en objektreference, påberåbe sig klon ()
på denne reference og kast det returnerede objekt fra Objekt
til den type genstand, der klones. Liste 3 viser et eksempel.
Liste 3. Kloning af et objekt
offentlig klasse CloneDemo implementerer Cloneable {int x; offentlig statisk ugyldig hoved (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); }}
Liste 3 erklærer en CloneDemo
klasse, der implementerer Klonabel
interface. Denne grænseflade skal implementeres eller en påkaldelse af Objekt
's klon ()
metode vil resultere i et kast CloneNotSupportedException
eksempel.
CloneDemo
erklærer en singel int
-baseret instansfelt navngivet x
og en hoved ()
metode, der udøver denne klasse. hoved ()
erklæres med en kasteklausul, 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 påberåber sig 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
Spørgsmål: Hvorfor skal jeg tilsidesætte klon ()
metode?
EN: Det forrige eksempel behøvede ikke at tilsidesætte klon ()
metode, fordi den kode, der påberåber sig klon ()
er placeret i klassen, der klones (dvs. CloneDemo
klasse). Men hvis den klon ()
påkaldelse er placeret i en anden klasse, skal du tilsidesætte klon ()
. Ellers modtager du en "klon har beskyttet adgang i Objekt
"besked fordi klon ()
erklæres beskyttet
. Listing 4 præsenterer en refactored Listing 3 for at demonstrere 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 (); }} public class CloneDemo {public static void main (String [] args) throw 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); }}
Fortegnelse 4 erklærer en Data
klasse, hvis forekomster skal klones. Denne klasse implementerer Klonabel
interface for at forhindre CloneNotSupportedException
fra at blive kastet, når klon ()
metode kaldes, erklærer int
-baseret instansfelt x
og tilsidesætter klon ()
metode. Denne metode udføres super.clone ()
at påberåbe sig sin superklasse (Objekt
i dette eksempel) klon ()
metode. Den altoverskyggende klon ()
metode identificerer CloneNotSupportedException
i sit kast klausul.
Liste 4 erklærer også a CloneDemo
klasse, der instantierer Data
, initialiserer sit forekomsterfelt, udsender værdien af denne forekomsts forekomsterfelt, kloner Data
forekomst og outputter denne instanss eksempelfeltvæ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
Spørgsmål: Hvad er lav kloning?
EN:Lav kloning (også kendt som lav kopiering) er duplikering af et objekts felter uden at duplikere nogen objekter, der henvises til fra objektets referencefelter (hvis det har nogen). Liste 3 og 4 viser 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 primitiv type, og (i mange tilfælde), når der henvises til 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). Listing 5 præsenterer en demonstration.
Fortegnelse 5. Demonstration af 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; }} offentlig klasse CloneDemo {offentlig statisk ugyldig hoved (String [] args) kaster CloneNotSupportedException {Medarbejder e = ny medarbejder ("John Doe", 49, ny adresse ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Medarbejder e2 = (Medarbejder) 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 ()); }}
Notering 5 gaver Medarbejder
, Adresse
og CloneDemo
klasser. Medarbejder
erklærer navn
, alder
og 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
Spørgsmål: Hvad er dyb kloning?
EN:Dyb kloning (også kendt som dyb kopiering) er duplikering af et objekts felter, således at eventuelle refererede objekter duplikeres. Derudover duplikeres deres refererede objekter - og så videre. For eksempel, Listing 6 refactors Listing 5 for at udnytte dyb kloning. Det demonstrerer også kovariante returtyper og en mere fleksibel måde at klone på.
Liste 6. Dybt kloning af adresse
Mark
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 offentlig medarbejderklon () kaster CloneNotSupportedException {Medarbejder e = (Medarbejder) super.clone (); e.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 Address klon () {returner ny adresse (ny streng (by)); } String getCity () {return city; } ugyldig setCity (strengby) {this.city = by; }} offentlig klasse CloneDemo {offentlig statisk ugyldig hoved (String [] args) kaster CloneNotSupportedException {Medarbejder e = ny medarbejder ("John Doe", 49, ny adresse ("Denver")); System.out.printf ("% s:% d:% s% n", e.getName (), e.getAge (), e.getAddress (). GetCity ()); Medarbejder e2 = (Medarbejder) 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 ()); }}
Fortegnelse 6 udnytter Java's understøttelse af covariante returtyper for at ændre returneringstypen af Medarbejder
er overordnet klon ()
metode fra Objekt
til Medarbejder
. Fordelen er, at kode uden for Medarbejder
kan klone en Medarbejder
objekt uden at skulle kaste dette objekt til Medarbejder
type.
Medarbejder
's klon ()
metode påberåber sig først super.clone ()
, som lavt kopierer navn
, alder
og adresse
felter. Det påberåber sig derefter klon ()
på den adresse
felt for at lave en kopi af den refererede Adresse
objekt.
Det Adresse
klasse tilsidesætter klon ()
metode og afslører et par forskelle fra tidligere klasser, der tilsidesætter denne metode:
Adresse
implementerer ikkeKlonabel
. Det er ikke nødvendigt, fordi kunObjekt
'sklon ()
metoden kræver, at en klasse implementerer denne grænseflade, og detteklon ()
metode kaldes ikke.- Den altoverskyggende
klon ()
metoden kaster ikkeCloneNotSupportedException
. Denne afkrydsede undtagelse kastes kun fraObjekt
'sklon ()
metode, som ikke kaldes. Derfor behøver undtagelsen ikke at blive håndteret eller videregivet metoden-opkaldstakken via en kasteklausul. Objekt
'sklon ()
metode kaldes ikke (der er ingensuper.clone ()
opkald) fordi overfladisk kopiering ikke er påkrævet forAdresse
klasse - der er kun et enkelt felt at kopiere.
At klone Adresse
objekt, er det tilstrækkeligt at oprette et nyt Adresse
objekt og initialiser det til en duplikat af det objekt, der henvises til fra by
Mark. Den nye Adresse
genstand returneres derefter.