CodeGym /Java blogg /Slumpmässig /Breddning och avsmalning av referenstyper
John Squirrels
Nivå
San Francisco

Breddning och avsmalning av referenstyper

Publicerad i gruppen
Hej! I en tidigare lektion diskuterade vi gjutning av primitiva typer. Låt oss kort påminna om vad som diskuterades. Utvidgning och avsmalning av referenstyper - 1Vi föreställde oss primitiva typer (i det här fallet numeriska typer) som häckande dockor som varierar i storlek beroende på hur mycket minne de upptar. Som du kommer ihåg är det enkelt att sätta in en mindre docka i en större både i verkligheten och i Java-programmering.

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
Detta är ett exempel på automatisk konvertering eller breddning . Det händer av sig självt, så du behöver inte skriva ytterligare kod. I slutändan gör vi inget ovanligt: ​​vi lägger bara en mindre docka i en större docka. Det är en annan sak om vi försöker göra tvärtom och lägga en större rysk docka i en mindre docka. Du kan inte göra det i verkligheten, men i programmering kan du. Men det finns en nyans. Om vi ​​försöker lägga in en inti en shortvariabel går det inte så smidigt för oss. När allt kommer omkring shortinnehåller variabeln bara 16 bitar information, men en intupptar 32 bitar! Som ett resultat förvrängs det godkända värdet. Kompilatorn kommer att ge oss ett fel (" Dude, du gör något misstänkt!'). Men om vi uttryckligen anger vilken typ vi konverterar vårt värde till, kommer den att utföra operationen.

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Det är precis vad vi gjorde i exemplet ovan. Operationen utfördes, men eftersom shortvariabeln endast kan rymma 16 av de 32 byten, förvrängs slutvärdet och vi får talet -27008 . En sådan operation kallas en explicit omvandling, eller avsmalning .

Exempel på breddning och avsmalning av referenstyper

Låt oss nu prata om samma operatorer som inte tillämpas på primitiva typer, utan på objekt och referensvariabler ! Hur fungerar detta i Java? Det är faktiskt ganska enkelt. Det finns objekt som inte är relaterade. Det skulle vara logiskt att anta att de inte kan konverteras till varandra, varken explicit eller automatiskt:

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

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

   }

}
Här får vi förstås ett fel. Klasserna Catoch Dogär inte relaterade till varandra, och vi har inte skrivit en "omvandlare" för att flytta från den ena till den andra. Det är vettigt att vi inte kan göra detta: kompilatorn har ingen aning om hur man konverterar dessa objekt från en typ till en annan. Om föremålen är relaterade, ja, det är en annan sak! Relaterat hur? Framför allt genom arv. Låt oss försöka använda arv för att skapa ett litet system med klasser. Vi kommer att ha en gemensam klass för att representera djur:

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
Alla vet att djur kan vara domesticerade (husdjur) eller vilda:

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");
   }
}
Ta till exempel hundar — vi har tamhundar och prärievargar:

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 valde specifikt de mest grundläggande klasserna för att göra dem lättare att förstå. Vi behöver egentligen inga fält, och det räcker med en metod. Låt oss prova att köra den här koden:

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Vad tror du kommer att visas på konsolen? Kommer introducemetoden för Petklassen eller Animalklassen att anropas? Försök motivera ditt svar innan du fortsätter läsa. Och här är resultatet! Jag är Pet Varför fick vi det? Det hela är enkelt. Vi har en överordnad variabel och ett efterkommande objekt. Genom att skriva,

Animal animal = new Pet();
vi utökade en Petreferens och tilldelade den till en Animalvariabel. Precis som med primitiva typer breddas referenstyper automatiskt i Java. Du behöver inte skriva ytterligare kod för att få det att hända. Nu har vi ett underordnat objekt tilldelat en överordnad referens. Som ett resultat ser vi att metodanropet görs på descendant-klassen. Om du fortfarande inte helt förstår varför den här koden fungerar, skriv om den på vanligt språk:

Animal animal = new DomesticatedAnimal();
Det är inga problem med detta, eller hur? Föreställ dig att detta är det verkliga livet, och referensen är helt enkelt en pappersetikett med "Animal" skrivet på. Om du tar den biten papper och fäster den i halsbandet på ett husdjur, kommer allt att bli korrekt. När allt kommer omkring är alla husdjur ett djur! Den omvända processen - att flytta ner i arvsträdet till ättlingar - minskar:

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Som du kan se anger vi här tydligt vilken klass vi vill konvertera vårt objekt till. Vi hade tidigare en WildAnimalvariabel, och nu har vi en , Coyotesom är lägre på arvsträdet. Det är vettigt att utan en explicit indikation kommer kompilatorn inte att tillåta en sådan operation, men om vi anger typen inom parentes så fungerar allt. Utvidgning och avsmalning av referenstyper - 2Tänk på ett annat mer intressant exempel:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
Kompilatorn genererar ett fel! Men varför? Eftersom du försöker tilldela ett överordnat objekt till en underordnad referens. Med andra ord, du försöker göra något så här:

DomesticatedAnimal domesticatedAnimal = new Animal();
Tja, kanske allt fungerar om vi uttryckligen anger vilken typ vi försöker konvertera till? Det fungerade med siffror — låt oss prova! :)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Undantag i tråden "huvud" java.lang.ClassCastException: Djur kan inte castas till Pet Fel! Kompilatorn skrek inte på oss den här gången, men det slutade med ett undantag. Vi vet redan anledningen: vi försöker tilldela ett överordnat objekt till en underordnad referens. Men varför exakt kan du inte göra det? Eftersom inte alla djur är tama djur. Du skapade ett Animalobjekt och försöker tilldela det till en Petvariabel. En prärievarg är också en Animal, men den är inte en Pet. Med andra ord, när du skriver

Pet pet = (Pet) new Animal();
new Animal()kan representera vilket djur som helst, inte nödvändigtvis ett husdjur! Pet petNaturligtvis är din variabel endast lämplig för förvaring av husdjur (och deras avkomlingar) och inte alla typer av djur. Det är därför ett speciellt Java-undantag, , ClassCastExceptionskapades för fall där ett fel uppstår under casting av klasser. Låt oss granska det igen för att göra saker tydligare. En överordnad referens kan peka på instanser av en understigande klass:

public class Main {

   public static void main(String[] args) {

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

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Här har vi till exempel inga problem. Vi har ett Petobjekt som refereras av en Petvariabel. Senare Animalpekade en referens på samma föremål. Efter det konverterar vi animaltill en Pet. Förresten, varför fungerade det för oss? Förra gången fick vi ett undantag! För den här gången är vårt ursprungliga objekt en Pet!

Pet pet = new Pet();
Men i det sista exemplet var det ett Animalobjekt:

Pet pet = (Pet) new Animal();
Du kan inte tilldela ett förfaderobjekt till en understigande variabel. Du kan göra tvärtom.
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION