CodeGym /Java blog /Tilfældig /Udvidelse og indsnævring af referencetyper
John Squirrels
Niveau
San Francisco

Udvidelse og indsnævring af referencetyper

Udgivet i gruppen
Hej! I en tidligere lektion diskuterede vi støbning af primitive typer. Lad os kort huske, hvad der blev diskuteret. Udvidelse og indsnævring af referencetyper - 1Vi forestillede os primitive typer (i dette tilfælde numeriske typer) som rededukker, der varierer i størrelse afhængigt af mængden af ​​hukommelse, de optager. Som du vil huske, er det nemt at sætte en mindre dukke i en større både i det virkelige liv og i Java-programmering.

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
Dette er et eksempel på automatisk konvertering eller udvidelse . Det sker af sig selv, så du behøver ikke skrive ekstra kode. I sidste ende gør vi ikke noget usædvanligt: ​​vi putter bare en mindre dukke ind i en større dukke. Det er en anden sag, hvis vi forsøger at gøre det modsatte og sætte en større russisk dukke ind i en mindre dukke. Det kan man ikke i det virkelige liv, men i programmering kan man. Men der er én nuance. Hvis vi forsøger at sætte en intind i en shortvariabel, går det ikke så glat for os. Variablen rummer jo shortkun 16 bit information, men en intoptager 32 bit! Som et resultat forvrænges den beståede værdi. Compileren vil give os en fejl (" Dude, du gør noget mistænkeligt!'). Men hvis vi udtrykkeligt angiver den type, som vi konverterer vores værdi til, vil den gå videre og udføre operationen.

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Det er lige, hvad vi gjorde i eksemplet ovenfor. Operationen blev udført, men fordi shortvariablen kun kan rumme 16 af de 32 bytes, bliver den endelige værdi forvrænget, og vi får tallet -27008 . En sådan operation kaldes en eksplicit konvertering eller indsnævring .

Eksempler på udvidelse og indsnævring af referencetyper

Lad os nu tale om de samme operatorer, der ikke anvendes på primitive typer, men på objekter og referencevariabler ! Hvordan fungerer dette i Java? Det er faktisk ret simpelt. Der er genstande, der ikke er relaterede. Det ville være logisk at antage, at de ikke kan konverteres til hinanden, hverken eksplicit eller automatisk:

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog(); // Error!

   }

}
Her får vi selvfølgelig en fejl. Klasserne Catog Doger ikke relateret til hinanden, og vi har ikke skrevet en 'konverter' til at flytte fra den ene til den anden. Det giver mening, at vi ikke kan gøre dette: compileren har ingen idé om, hvordan man konverterer disse objekter fra den ene type til den anden. Hvis objekterne er beslægtede, ja, det er en anden sag! Relateret hvordan? Frem for alt gennem arv. Lad os prøve at bruge arv til at skabe et lille system af klasser. Vi får en fælles klasse til at repræsentere dyr:

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
Alle ved, at dyr kan være tæmmede (kæledyr) eller vilde:

public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("I'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("I'm Pet");
   }
}
Tag for eksempel hjørnetænder - vi har tamhunde og prærieulve:

public class Dog extends Pet {

   public void introduce() {

       System.out.println("I'm Dog");
   }
}



public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println ("I'm Coyote");
   }
}
Vi har specifikt valgt de mest basale klasser for at gøre dem nemmere at forstå. Vi har ikke rigtig brug for nogle felter, og én metode er nok. Lad os prøve at udføre denne kode:

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Hvad tror du vil blive vist på konsollen? Vil introduceklassens Peteller Animalklassens metode blive påberåbt? Prøv at begrunde dit svar, før du fortsætter med at læse. Og her er resultatet! Jeg er Pet Hvorfor fik vi det? Det hele er enkelt. Vi har en overordnet variabel og et efterkommerobjekt. Ved at skrive,

Animal animal = new Pet();
vi udvidede en Petreference og tildelte den til en Animalvariabel. Som med primitive typer udvides referencetyper automatisk i Java. Du behøver ikke at skrive yderligere kode for at få det til at ske. Nu har vi et efterkommerobjekt tildelt en overordnet reference. Som et resultat ser vi, at metodekaldet foretages på descendant-klassen. Hvis du stadig ikke helt forstår, hvorfor denne kode virker, så omskriv den i almindeligt sprog:

Animal animal = new DomesticatedAnimal();
Det er der ikke noget problem med, vel? Forestil dig, at dette er det virkelige liv, og referencen er simpelthen en papirlabel med 'Animal' skrevet på. Hvis du tager det stykke papir og fastgør det til halsbåndet på et kæledyr, vil alt være korrekt. Ethvert kæledyr er trods alt et dyr! Den omvendte proces - at flytte ned i arvetræet til efterkommere - er indsnævret:

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Som du kan se, angiver vi her tydeligt den klasse, som vi ønsker at konvertere vores objekt til. Vi havde tidligere en WildAnimalvariabel, og nu har vi en Coyote, som er lavere på arvetræet. Det giver mening, at uden en eksplicit indikation vil compileren ikke tillade en sådan operation, men hvis vi angiver typen i parentes, så fungerer alt. Udvidelse og indsnævring af referencetyper - 2Overvej et andet mere interessant eksempel:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
Compileren genererer en fejl! Men hvorfor? Fordi du forsøger at tildele et overordnet objekt til en efterkommerreference. Med andre ord, du prøver at gøre noget som dette:

DomesticatedAnimal domesticatedAnimal = new Animal();
Nå, måske vil alt fungere, hvis vi udtrykkeligt angiver den type, vi forsøger at konvertere til? Det fungerede med tal - lad os prøve det! :)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Undtagelse i tråden "hoved" java.lang.ClassCastException: Dyr kan ikke castes til Pet Fejl! Compileren råbte ikke ad os denne gang, men vi endte med en undtagelse. Vi kender allerede årsagen: vi forsøger at tildele et overordnet objekt til en efterkommerreference. Men hvorfor lige præcis kan du ikke det? Fordi ikke alle dyr er tæmmede dyr. Du har oprettet et Animalobjekt og forsøger at tildele det til en Petvariabel. En coyote er også en Animal, men den er ikke en Pet. Med andre ord, når du skriver

Pet pet = (Pet) new Animal();
new Animal()kunne repræsentere ethvert dyr, ikke nødvendigvis et kæledyr! Naturligvis er din Pet petvariabel kun egnet til opbevaring af kæledyr (og deres efterkommere) og ikke enhver type dyr. Det er derfor, der blev oprettet en særlig Java-undtagelse, ClassCastException, for tilfælde, hvor der opstår en fejl under casting af klasser. Lad os gennemgå det igen for at gøre tingene klarere. En overordnet reference kan pege på forekomster af en efterkommerklasse:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
For eksempel her har vi ingen problemer. Vi har et Petobjekt, der refereres til af en Petvariabel. Senere Animalpegede en reference på det samme objekt. Derefter konverterer vi animaltil en Pet. Forresten, hvorfor virkede det for os? Sidste gang fik vi en undtagelse! For denne gang er vores originale objekt en Pet!

Pet pet = new Pet();
Men i det sidste eksempel var det et Animalobjekt:

Pet pet = (Pet) new Animal();
Du kan ikke tildele et forfaderobjekt til en efterkommervariabel. Du kan gøre det modsatte.
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION