CodeGym /Blog Java /Aleatoriu /Lărgirea și îngustarea tipurilor de referință
John Squirrels
Nivel
San Francisco

Lărgirea și îngustarea tipurilor de referință

Publicat în grup
Bună! Într-o lecție trecută, am discutat despre turnarea tipurilor primitive. Să ne amintim pe scurt ce s-a discutat. Lărgirea și îngustarea tipurilor de referință - 1Ne-am imaginat tipurile primitive (în acest caz, tipuri numerice) ca niște păpuși de cuib care variază în dimensiune în funcție de cantitatea de memorie pe care o ocupă. După cum vă veți aminti, introducerea unei păpuși mai mici în una mai mare este simplă atât în ​​viața reală, cât și în programarea Java.

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
Acesta este un exemplu de conversie sau extindere automată . Se întâmplă de la sine, așa că nu trebuie să scrieți cod suplimentar. În cele din urmă, nu facem nimic neobișnuit: doar punem o păpușă mai mică într-o păpușă mai mare. Este o altă chestiune dacă încercăm să facem invers și să punem o păpușă rusească mai mare într-o păpușă mai mică. Nu poți face asta în viața reală, dar în programare poți. Dar există o nuanță. Dacă încercăm să punem un intîntr-o shortvariabilă, lucrurile nu merg atât de bine pentru noi. La urma urmei, shortvariabila deține doar 16 biți de informații, dar an intocupă 32 de biți! Ca urmare, valoarea transmisă este distorsionată. Compilatorul ne va da o eroare (' Omule, faci ceva suspect!'). Dar dacă indicăm în mod explicit tipul în care ne convertim valoarea, acesta va continua și va efectua operația.

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Exact asta am făcut în exemplul de mai sus. Operația a fost efectuată, dar pentru că shortvariabila poate găzdui doar 16 din cei 32 de octeți, valoarea finală este distorsionată și obținem numărul -27008 . O astfel de operație se numește conversie explicită sau îngustare .

Exemple de lărgire și îngustare a tipurilor de referință

Acum să vorbim despre aceiași operatori aplicați nu la tipurile primitive, ci la obiecte și variabile de referință ! Cum funcționează asta în Java? De fapt, este destul de simplu. Sunt obiecte care nu au legătură. Ar fi logic să presupunem că nu pot fi convertite unul la altul, nici explicit, nici automat:

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

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

   }

}
Aici, desigur, primim o eroare. Clasele Catși Dognu sunt legate între ele și nu am scris un „convertor” pentru a trece de la una la alta. Este logic că nu putem face asta: compilatorul nu are idee cum să convertească aceste obiecte de la un tip la altul. Dacă obiectele sunt legate, ei bine, asta e altă chestiune! Legat cum? Mai presus de toate, prin moștenire. Să încercăm să folosim moștenirea pentru a crea un mic sistem de clase. Vom avea o clasă comună pentru a reprezenta animalele:

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
Toată lumea știe că animalele pot fi domesticite (animale de companie) sau sălbatice:

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");
   }
}
De exemplu, luați canini - avem câini domestici și coioți:

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");
   }
}
Am ales în mod special cele mai elementare clase pentru a le face mai ușor de înțeles. Nu prea avem nevoie de câmpuri și este suficientă o singură metodă. Să încercăm să executăm acest cod:

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Ce crezi că va fi afișat pe consolă? Se va invoca introducemetoda clasei Petsau a clasei? AnimalÎncercați să vă justificați răspunsul înainte de a continua să citiți. Și iată rezultatul! Sunt Pet De ce am primit asta? Totul este simplu. Avem o variabilă părinte și un obiect descendent. În scris,

Animal animal = new Pet();
am lărgit o Petreferință și am atribuit-o unei Animalvariabile. Ca și în cazul tipurilor primitive, tipurile de referință sunt extinse automat în Java. Nu trebuie să scrieți cod suplimentar pentru a face acest lucru. Acum avem un obiect descendent alocat unei referințe părinte. Ca urmare, vedem că apelul de metodă se face pe clasa descendentă. Dacă încă nu înțelegeți pe deplin de ce funcționează acest cod, rescrieți-l într-un limbaj simplu:

Animal animal = new DomesticatedAnimal();
Nu e nicio problemă cu asta, nu? Imaginați-vă că aceasta este viața reală, iar referința este pur și simplu o etichetă de hârtie cu „Animal” scris pe ea. Dacă luați acea bucată de hârtie și o atașați de gulerul oricărui animal de companie, totul va fi corect. La urma urmei, orice animal de companie este un animal! Procesul invers - deplasarea în jos a arborelui moștenire la descendenți - se îngustează:

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
După cum puteți vedea, aici indicăm în mod clar clasa în care dorim să convertim obiectul nostru. Am avut anterior o WildAnimalvariabilă, iar acum avem o Coyote, care este mai jos în arborele de moștenire. Este logic că, fără o indicație explicită, compilatorul nu va permite o astfel de operație, dar dacă indicăm tipul în paranteze, atunci totul funcționează. Lărgirea și îngustarea tipurilor de referință - 2Luați în considerare un alt exemplu mai interesant:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
Compilatorul generează o eroare! Dar de ce? Pentru că încercați să atribuiți un obiect părinte unei referințe descendente. Cu alte cuvinte, încerci să faci ceva de genul acesta:

DomesticatedAnimal domesticatedAnimal = new Animal();
Ei bine, poate totul va funcționa dacă specificăm în mod explicit tipul în care încercăm să facem conversia? A funcționat cu numere — Să încercăm! :)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Excepție în firul „principal” java.lang.ClassCastException: Animalul nu poate fi aruncat la Pet Error! Compilatorul nu a țipat la noi de data aceasta, dar am ajuns cu o excepție. Știm deja motivul: încercăm să atribuim un obiect părinte unei referințe descendente. Dar de ce nu poți face asta? Pentru că nu toate animalele sunt animale domestice. Ați creat un Animalobiect și încercați să-l atribuiți unei Petvariabile. Un coiot este, de asemenea, un Animal, dar nu este un Pet. Cu alte cuvinte, când scrii

Pet pet = (Pet) new Animal();
new Animal()ar putea reprezenta orice animal, nu neapărat un animal de companie! Desigur, variabila dvs. Pet peteste potrivită doar pentru stocarea animalelor de companie (și a descendenților acestora) și nu a oricărui tip de animal. De aceea, ClassCastExceptiona fost creată o excepție Java specială, , pentru cazurile în care apare o eroare la turnarea claselor. Să-l revizuim din nou pentru a clarifica lucrurile. O referință părinte poate indica instanțe ale unei clase descendente:

public class Main {

   public static void main(String[] args) {

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

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
De exemplu, aici nu avem probleme. Avem un Petobiect referit printr-o Petvariabilă. Mai târziu, o Animalreferință a îndreptat spre același obiect. După aceea, convertim animalîntr-un Pet. Apropo, de ce a funcționat pentru noi? Ultima dată am avut o excepție! Pentru că de data aceasta obiectul nostru original este un Pet!

Pet pet = new Pet();
Dar în ultimul exemplu, era un Animalobiect:

Pet pet = (Pet) new Animal();
Nu puteți atribui un obiect strămoș unei variabile descendente. Poți să faci invers.
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION