CodeGym/Java Blog/Willekeurig/Verbreding en vernauwing van primitieve typen
John Squirrels
Niveau 41
San Francisco

Verbreding en vernauwing van primitieve typen

Gepubliceerd in de groep Willekeurig
Hoi! Naarmate je verder bent gekomen in CodeGym, ben je vaak primitieve typen tegengekomen. Hier is een korte lijst van wat we over hen weten:
  1. Het zijn geen objecten en vertegenwoordigen een waarde die in het geheugen is opgeslagen
  2. Er zijn verschillende soorten
    • Gehele getallen: byte , short , int , long
    • Floating-point (fractionele) getallen: float en double
    • Logische waarden: booleaans
    • Symbolische waarden (voor weergave van letters en cijfers): char
  3. Elk type heeft zijn eigen waardenbereik:

Primitieve soort Grootte in het geheugen Waardebereik
byte 8 bits -128 tot 127
kort 16 bits -32768 tot 32767
char 16 bits 0 tot 65536
int 32 bits -2147483648 tot 2147483647
lang 64 bits -9223372036854775808 tot 9223372036854775807
vlot 32 bits (2 tot de macht van -149) tot ((2 - (2 tot de macht van -23)) * 2 tot de macht van 127)
dubbele 64 bits (-2 tot de macht van 63) tot ((2 tot de macht van 63) - 1)
booleaans 8 (indien gebruikt in arrays), 32 (indien niet gebruikt in arrays) waar of niet waar
Maar behalve dat ze verschillende waarden hebben, verschillen ze ook in de hoeveelheid ruimte die ze in het geheugen innemen. Een int duurt meer dan een byte. En een lange is groter dan een korte. De hoeveelheid geheugen die door primitieven wordt ingenomen, kan worden vergeleken met Russische nestpoppen: Verbreding en vernauwing van primitieve typen - 2 elke nestpop heeft binnenin ruimte beschikbaar. Hoe groter de nestpop, hoe meer ruimte er is. Een grote nestpop ( lang ) zal gemakkelijk een kleinere int huisvesten . Het past gemakkelijk en je hoeft verder niets te doen. In Java wordt dit bij het werken met primitieven impliciete conversie genoemd. Of anders gezegd, het wordt verbreding genoemd.

Verbreding op Java

Hier is een eenvoudig voorbeeld van een verbredende conversie:
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       byte littleNumber = 16;

       bigNumber = littleNumber;
       System.out.println(bigNumber);
   }
}
Hier kennen we een bytewaarde toe aan een int- variabele. De toewijzing lukt zonder problemen: de waarde die in een byte is opgeslagen, neemt minder geheugen in beslag dan wat een int aankan. De kleine nestpop (bytewaarde) past gemakkelijk in de grote nestpop ( int- variabele). Het is een andere zaak als je het tegenovergestelde probeert te doen, dwz een grote waarde in een variabele stopt waarvan het bereik niet geschikt is voor zo'n type big data. Met echte nestpoppen zou het aantal gewoon niet passen. Met Java kan het, maar met nuances. Laten we proberen een int in een korte variabele te plaatsen:
public static void main(String[] args) {

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = bigNumber;// Error!
   System.out.println(bigNumber);
}
Fout! De compiler begrijpt dat je iets abnormaals probeert te doen door een grote pop ( int ) in een kleine ( short ) te schuiven. In dit geval is de compilatiefout een waarschuwing van de compiler: "Hé, weet je absoluut zeker dat je dit wilt doen?" Als je het zeker weet, zeg je tegen de compiler: "Alles is in orde. Ik weet wat ik doe!" Dit proces wordt expliciete typeconversie of vernauwing genoemd.

Vernauwing op Java

Om een ​​vernauwende conversie uit te voeren, moet u expliciet aangeven naar welk type u uw waarde wilt converteren. Met andere woorden, je moet de vraag van de samensteller beantwoorden: "Nou, in welke van deze kleine nestpoppen wil je deze grote nestpop zetten?" In ons geval ziet het er zo uit:
public static void main(String[] args) {

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = (short) bigNumber;
   System.out.println(littleNumber);
}
We geven expliciet aan dat we een int in een korte variabele willen stoppen en dat we de verantwoordelijkheid nemen. Aangezien er expliciet een smaller type is aangegeven, voert de compiler de conversie uit. Wat is het resultaat? Console-uitvoer: -27008 Dat was een beetje onverwacht. Waarom hebben we dat precies gekregen? Eigenlijk is het allemaal heel simpel. Oorspronkelijk was de waarde 10000000. Het werd opgeslagen in een int- variabele, die 32 bits in beslag neemt. Dit is de binaire weergave:
Verbreding en vernauwing van primitieve typen - 3
We schrijven deze waarde in een korte variabele, die maar 16 bits kan opslaan! Dienovereenkomstig worden alleen de eerste 16 bits van ons nummer daarheen verplaatst. De rest wordt weggegooid. Als resultaat krijgt de korte variabele de volgende waarde
Verbreding en vernauwing van primitieve typen - 4
wat in decimale vorm gelijk is aan -27008 Daarom vraagt ​​de compiler u om te "bevestigen" door een expliciete vernauwende conversie naar een specifiek type aan te geven. Ten eerste laat dit zien dat je verantwoordelijkheid neemt voor het resultaat. En ten tweede vertelt het de compiler hoeveel ruimte moet worden toegewezen tijdens het converteren. Als we in het laatste voorbeeld immers een int-waarde toekennen aan een bytevariabele in plaats van een short , dan zouden we maar 8 bits tot onze beschikking hebben, niet 16, en zou het resultaat anders zijn. Fractionele typen ( float en double ) hebben hun eigen proces voor het beperken van conversies. Als u een factienummer probeert te casten naar een geheel getal, wordt het fractionele deel weggegooid.
public static void main(String[] args) {

   double d = 2.7;

   long x = (int) d;
   System.out.println(x);
}
Console-uitgang: 2

char

U weet al dat char wordt gebruikt om individuele tekens weer te geven.
public static void main(String[] args) {

   char c = '!';
   char z = 'z';
   char i = '8';

}
Maar dit gegevenstype heeft verschillende kenmerken die belangrijk zijn om te begrijpen. Laten we nog eens kijken naar de tabel met waardebereiken:
Primitieve soort Grootte in het geheugen Waardebereik
byte 8 bits -128 tot 127
kort 16 bits -32768 tot 32767
char 16 bits 0 tot 65536
int 32 bits -2147483648 tot 2147483647
lang 64 bits -9223372036854775808 tot 9223372036854775807
vlot 32 bits (2 tot de macht van -149) tot ((2 - (2 tot de macht van -23)) * 2 tot de macht van 127)
dubbele 64 bits (-2 tot de macht van 63) tot ((2 tot de macht van 63) - 1)
booleaans 8 (indien gebruikt in arrays), 32 (indien niet gebruikt in arrays) waar of niet waar
Het bereik 0 tot 65536 wordt aangegeven voor het tekentype . Maar wat betekent dat? Een teken staat immers niet alleen voor cijfers, maar ook voor letters, leestekens… Het punt is dat in Java tekenwaarden worden opgeslagen in Unicode-indeling. Unicode kwamen we al tegen in een van de vorige lessen. U herinnert zich waarschijnlijk dat Unicode een tekencoderingsstandaard is die de symbolen van bijna alle geschreven talen van de wereld bevat. Met andere woorden, het is een lijst met speciale codes die bijna elk teken in elke taal vertegenwoordigen. De hele Unicode-tabel is erg groot en het is natuurlijk niet nodig om deze uit het hoofd te leren. Hier is een klein deel ervan: Verbreding en vernauwing van primitieve typen - 5 Het belangrijkste is om te begrijpen hoe tekens worden opgeslagen, en om te onthouden dat als je de code voor een bepaald teken kent, je dat teken altijd in je programma kunt produceren. Laten we het eens proberen met een willekeurig getal:
public static void main(String[] args) {

   int x = 32816;

   char c = (char) x ;
   System.out.println(c);
}
Console-uitvoer: 耰 Dit is de indeling die wordt gebruikt om tekens in Java op te slaan. Elk symbool komt overeen met een nummer: een 16-bits (twee bytes) numerieke code. In Unicode komt 32816 overeen met het Chinese karakter 耰. Noteer het volgende punt. In dit voorbeeld hebben we een int- variabele gebruikt. Het neemt 32 bits geheugen in beslag, terwijl een char er 16 in beslag neemt. Hier hebben we een int gekozen , omdat ons nummer (32816) niet in een kort past . Hoewel de grootte van een teken (net als een korte ) 16 bits is, zijn er geen negatieve getallen in het tekenbereik , dus het "positieve" deel van het tekenbereik is twee keer zo groot (65536 in plaats van 32767 voor het korte type). We kunnen een int gebruiken zolang onze code onder 65536 blijft. Maar als u een int- waarde groter dan 65536 maakt, zal deze meer dan 16 bits in beslag nemen. En dit zal resulteren in een versmallende conversie
char c = (char) x;
de extra bits worden weggegooid (zoals hierboven besproken) en het resultaat zal vrij onverwacht zijn.

Speciale kenmerken van het toevoegen van tekens en gehele getallen

Laten we een ongebruikelijk voorbeeld bekijken:
public class Main {

   public static void main(String[] args) {

      char c = '1';

      int i = 1;

       System.out.println(i + c);
   }
}
Console-uitvoer: 50 O_О Hoe logisch is dat? 1+1. Waar komt de 50 vandaan?! U weet al dat charwaarden in het geheugen worden opgeslagen als getallen in het bereik van 0 tot 65536, en dat deze getallen een Unicode-weergave van een teken zijn. Wanneer we een teken en een type met een geheel getal Verbreding en vernauwing van primitieve typen - 6 toevoegen , wordt het teken geconverteerd naar het overeenkomstige Unicode-nummer. Toen we in onze code 1 en '1' toevoegden, werd het symbool '1' geconverteerd naar zijn eigen code, namelijk 49 (je kunt dit verifiëren in de bovenstaande tabel). Daarom is het resultaat 50. Laten we nogmaals onze oude vriend 耰 als voorbeeld nemen en deze proberen op te tellen bij een getal.
public static void main(String[] args) {

   char c = '耰';
   int x = 200;

   System.out.println(c + x);
}
Console-uitvoer: 33016 We hebben al ontdekt dat 耰 overeenkomt met 32816. En als we dit getal en 200 optellen, krijgen we ons resultaat: 33016. :) Zoals je kunt zien, is het algoritme hier vrij eenvoudig, maar je moet het niet vergeten .
Opmerkingen
  • Populair
  • Nieuw
  • Oud
Je moet ingelogd zijn om opmerkingen te kunnen maken
Deze pagina heeft nog geen opmerkingen