De auteur heeft het Vrij en Open Source Fonds geselecteerd om een donatie te ontvangen als onderdeel van het programma Schrijf voor Donaties.
Introductie
Java is een statisch getypeerde programmeertaal. Dit betekent dat wanneer je een variabele creëert, je ook zijn gegevenstype moet specificeren, dat is het type informatie dat het opslaat. Dit staat in contrast met dynamisch getypeerde talen, zoals PHP. Bij dynamisch getypeerde talen hoef je het gegevenstype van een variabele niet te specificeren, wat misschien een opluchting lijkt.
Echter, het kennen van de gegevenstypen en ze op de juiste manier gebruiken stelt ontwikkelaars in staat om hun code te optimaliseren omdat elk gegevenstype specifieke resourcevereisten heeft. Bovendien, als je één gegevenstype specificeert en probeert een ander type op te slaan, zoals per ongeluk, zul je de code niet kunnen compileren. Dus, met statisch getypeerde talen, kun je fouten detecteren zelfs voordat er enige testen zijn uitgevoerd.
Java heeft twee gegevenstypen: primitief en referentie (ook bekend als niet-primitief). In deze handleiding zul je variabelen gebruiken om informatie op te slaan en te gebruiken in een Java-programma, zodat je meer te weten komt over enkele veelgebruikte gegevenstypen in Java. Dit is geen uitputtend overzicht van alle gegevenstypen, maar deze gids zal je helpen vertrouwd te raken met de beschikbare opties in Java.
Vereisten
Om deze handleiding te volgen, heb je nodig:
-
Een omgeving waarin u Java-programma’s kunt uitvoeren om de voorbeelden te volgen. Om dit op uw lokale machine in te stellen, heeft u het volgende nodig:
- Java (versie 11 of hoger) geïnstalleerd op uw machine, met de compiler geleverd door de Java Development Kit (JDK). Voor Ubuntu en Debian, volg de stappen voor Optie 1 in onze handleiding, Hoe Java installeren met Apt op Ubuntu 22.04. Voor andere besturingssystemen, inclusief Mac en Windows, zie de downloadopties voor Java-installatie.
- Voor het compileren en uitvoeren van de codevoorbeelden maakt deze handleiding gebruik van Java Shell, een Read-Evaluate-Print Loop (REPL) uitgevoerd vanaf de opdrachtregel. Om aan de slag te gaan met JShell, bekijk de Inleiding tot JShell handleiding.
-
Bekendheid met Java en objectgeoriënteerd programmeren, die u kunt vinden in onze tutorial, Hoe u uw eerste programma in Java schrijft.
Primitieve Types
Java primitieve types zijn de eenvoudigste en meest fundamentele gegevenstypen in Java. Ze vertegenwoordigen rauwe waarden zoals getallen en tekens. De meest gebruikte primitieve gegevenstypen zijn int
(gehele getallen), boolean
(boolean-waarden) en char
(tekens). De overige typen zijn te vinden in de officiële Java gegevenstypen documentatie.
Gehele Getallen
Gehele getallen kunnen zowel negatieve als positieve gehele getallen zijn. In Java gebruik je int
om ze op te slaan. int
kan voldoende grote getallen bevatten voor de meeste doeleinden: van -2.147.483.648
tot 2.147.483.647
.
Laten we kijken hoe int
wordt gebruikt in een voorbeeld:
int theAnswer = 42;
Primitieve typen beginnen altijd met een kleine letter (int
). Java-syntaxisregels vereisen dat je eerst het gegevenstype opgeeft (int
) en vervolgens de naam ervan (hetAntwoord
). Daarna wijs je de waarde 42
toe met het is-gelijk-teken (=
) aan de variabele.
Ongeacht het gegevenstype gebruik je een variabele door rechtstreeks de naam op te geven zonder enige speciale tekens ervoor te plaatsen. Dit komt omdat Java het kan herkennen als een variabele.
Opmerking: De naam van de variabele theAnswer
en alle andere variabelen in deze zelfstudie zijn geschreven in Camelcase. Hoewel er geen strikte vereiste is om het te gebruiken, is dit de geaccepteerde naamgevingsconventie in Java.
Zodra je de variabele hebt gedeclareerd, kun je deze gebruiken door ernaar te verwijzen in een methode zoals deze:
int theAnswer = 42;
System.out.println("The answer to all questions is " + theAnswer);
In de tweede regel druk je theAnswer
af naar de console met behulp van de ingebouwde methode println
uit het pakket System.out
. Dit is de eenvoudigste manier om een variabele te testen om ervoor te zorgen dat deze zoals verwacht is gedeclareerd.
Om deze code in actie te zien, gebruik je de Java Shell-tool. Nadat je Java hebt geïnstalleerd, open je een terminal of opdrachtprompt op je lokale computer en typ je jshell
:
- jshell
Je uitvoer zal er ongeveer als volgt uitzien:
Output| Welcome to JShell -- Version 11.0.16
| For an introduction type: /help intro
jshell>
Je kunt de codevoorbeelden uit deze zelfstudie in de console plakken. Als je klaar bent, kun je jshell
afsluiten door /exit
in te typen.
Om int
te declareren en te gebruiken, plak je de volgende regels in de jshell
-console:
- int theAnswer = 42;
- System.out.println("The answer to all questions is " + theAnswer);
Je zult de volgende uitvoer zien:
OutputtheAnswer ==> 42
The answer to all questions is 42
Deze uitvoer bevestigt dat je de int
-variabele theAnswer
correct hebt ingesteld op 42 (theAnswer ==> 42
). Je hebt ook succesvol theAnswer
gebruikt door het door te geven aan een methode, en de methode produceerde de verwachte variabele waarde.
Boolean
Boolean waarden zijn true
of false
. In Java, gebruik je boolean
om ze op te slaan. Bijvoorbeeld, laten we een boolean
variabele aanmaken die aangeeft of Java leuk is:
boolean isJavaFun = true;
Je definieert de variabele isJavaFun
als true
. De alternatieve boolean
waarde is false
.
Met de bovenstaande variabele kan je de zin Java is fun: true
printen als volgt:
- boolean isJavaFun = true;
- System.out.println("Java is fun: " + isJavaFun);
Het uitvoeren van deze regels in jshell
zal de volgende uitvoer produceren:
OutputisJavaFun ==> true
Java is fun: true
Vergelijkbaar met het int
voorbeeld, zal de methode println
het argument dat in de haakjes is opgegeven printen. Het plus-teken (+
) concateneert of voegt de string “Java is fun: ” samen met de variabele isJavaFun
zodat het in werkelijkheid slechts één argument is — de string, Java is fun: true
.
Karakters
Om een enkel alfanumeriek karakter op te slaan, gebruik je char
. Bijvoorbeeld:
char firstLetter = 'a';
Merk op dat de letter a
wordt omringd door enkele aanhalingstekens. Enkele aanhalingstekens kunnen alleen worden gebruikt voor char
waarden. Dubbele aanhalingstekens worden gebruikt voor strings, zoals je later zult leren.
char
lijkt niet echt een nuttig type te zijn, omdat het niet waarschijnlijk is dat je een variabele nodig hebt toegewezen aan een enkel karakter. Echter, char
wordt gebruikt als het bouwsteen voor klassen van karakterreeksen zoals String
, die in feite een verzameling van char
-waarden zijn.
Zoals je hebt gezien in dit gedeelte, is de declaratie en het gebruik van variabelen van het primitieve type eenvoudig omdat ze eenvoudige waarden zoals integers vertegenwoordigen. Deze waarden zijn klaar voor gebruik en vereisen geen aanvullende bewerkingen zoals het maken van objecten, het aanroepen van methoden, enzovoort.
Referentietypen
In de eerste tutorial in deze serie, Hoe schrijf je je eerste programma in Java, heb je geleerd dat Java-code is georganiseerd in klassen en dat deze klassen worden gebruikt als sjablonen om objecten te maken. Wanneer dergelijke objecten aan variabelen worden toegewezen, wijs je naar of verwijs je naar deze objecten. In deze gevallen worden de variabelen geclassificeerd als referentietypen. Deze variabelen worden ook wel niet-primitief genoemd omdat variabelen van het primitieve type niet naar objecten kunnen wijzen.
Objecten zijn krachtig omdat ze geavanceerde eigenschappen hebben en in staat zijn om acties uit te voeren wanneer je hun methoden activeert. Zonder variabelen die naar hen wijzen, zijn deze objecten ontoegankelijk en praktisch onbruikbaar. Daarom zijn variabelen van het referentietype essentieel voor Java en objectgeoriënteerd programmeren in het algemeen.
Opmerking: Referentietypen wijzen naar objecten die zijn gemaakt van klassen. Om verwarring te voorkomen, zullen het referentietype en het gemaakte object in de volgende voorbeelden van dezelfde klasse zijn.
Echter, in complexe programma’s is dit zelden het geval. In Java is een interface een groep vereisten voor een specifiek gedrag, en deze vereisten kunnen worden vervuld door een of meer klassen. Een klasse die voldoet aan de vereisten van een interface wordt gezegd deze interface te implementeren. Daarom is het in complexe programma’s gebruikelijk om een variabele te declareren met het referentietype van een interface. Op deze manier specificeer je het gedrag dat je variabele moet vertonen zonder het te koppelen aan een concrete implementatie van dit gedrag. Hierdoor kun je eenvoudig wijzigen naar welke implementatie je variabele verwijst zonder de manier waarop de variabele wordt gebruikt te veranderen. Dit complexe concept maakt deel uit van een meer gevorderd onderwerp over overerving en polymorfisme, wat een aparte tutorial zal zijn in onze Java-serie.
Terwijl er slechts enkele primitieve types zijn, zijn referentietypes praktisch onbeperkt omdat er geen limiet is aan het aantal klassen (en interfaces), en elke klasse staat voor een referentietype. Er zijn veel ingebouwde klassen in Java die essentiële functionaliteit bieden. De meest gebruikte bevinden zich in het kernpakket java.lang
. Je zult er enkele van bespreken in deze sectie.
De klasse String
De klasse String
vertegenwoordigt een combinatie van tekens die een string vormen. Om een String
of een andere referentietypevariabele te declareren, geef je eerst het type ervan op, gevolgd door de naam. Daarna wijs je er een waarde aan toe met het is-gelijkteken. Tot nu toe lijkt het op werken met primitieve types. Referentietypes wijzen echter naar objecten, dus je moet een object maken als er nog geen is gemaakt. Hier is een voorbeeld:
String hello = new String("Hello");
hello
is de naam van de variabele met het referentietype String
. Je wijst het toe aan een nieuw String
-object. Het nieuwe String
-object wordt gemaakt met het new
-trefwoord samen met de naam van de klasse – in dit geval String
. De klasse String
begint met een hoofdletter. Volgens conventie beginnen alle klassen en dus referentietypes met een hoofdletter.
Elke klas heeft een speciale methode genaamd een constructor die wordt gebruikt voor het maken van nieuwe objecten. U kunt deze constructor oproepen door haakjes (()
) toe te voegen aan het einde van de klassenaam. De constructor kan parameters accepteren, zoals in het bovenstaande voorbeeld, waarbij de parameter "Hallo"
wordt toegepast op de constructor voor String
.
Om te bevestigen dat de variabele hello
zich gedraagt zoals verwacht, moet u deze opnieuw doorgeven aan de methode println
als volgt:
- String hello = new String("Hello");
- System.out.println(hello);
Het uitvoeren van deze regels in jshell
zal de volgende output produceren:
Outputhello ==> "Hello"
Hello
Deze keer bevestigt de uitvoer dat de variabele hello
is ingesteld op Hallo
. Daarna wordt dezelfde Hallo
afgedrukt op een nieuwe regel, waarbij wordt bevestigd dat de methode println()
deze heeft verwerkt.
Wrapper Klassen
In het vorige gedeelte heb je gewerkt met het referentietype String
, dat vaak wordt gebruikt. Andere populaire referentietypes zijn de zogenaamde wrappers voor primitieve types. Een wrapperklasse wikkelt of bevat primitieve gegevens, vandaar de naam. Alle primitieve typen hebben wrapper-tegenhangers, en hier zijn enkele voorbeelden:
Integer
: omint
waarden in te pakken.Character
: omchar
waarden in te pakken.Boolean
: omboolean
waarden in te pakken.
Deze wrappers bestaan zodat je een eenvoudige primitieve waarde kunt upgraden naar een krachtig object. Elke wrapper heeft kant-en-klare methoden die verband houden met de waarden waarvoor deze is ontworpen om op te slaan.
Als voorbeeld ga je Integer
verkennen. In het vorige gedeelte heb je een String
-object gemaakt met het new
-trefwoord. Sommige klassen bieden echter, en moedigen zelfs aan, het gebruik van speciale methoden om objecten van hen te verkrijgen, en Integer
is er een van. In het geval van Integer
gaat het gebruik van een speciale methode voornamelijk over optimalisatie van middelen, maar in andere gevallen kan het gaan om het vereenvoudigen van de constructie van complexe objecten.
In het volgende voorbeeld maak je bijvoorbeeld een Integer
-variabele genaamd theAnswer
met de waarde 42
met behulp van de valueOf
-methode:
- Integer theAnswer = Integer.valueOf(42);
- System.out.println(theAnswer);
In jshell
krijg je de volgende output:
OutputtheAnswer ==> 42
42
Door de Integer
-methode valueOf(42)
aan te roepen, geef je Java de opdracht om je een object met deze waarde te geven. Achter de schermen controleert Java of er al een object met zo’n waarde in de cache staat. Als dat het geval is, wordt het object gekoppeld aan de variabele theAnswer
. Als dat niet het geval is, wordt er een nieuw object gemaakt voor de variabele theAnswer
.
Veel ingebouwde klassen bieden dergelijke methoden om prestatieredenen, en het gebruik ervan wordt aanbevolen, zo niet verplicht. In het geval van Integer
zou je nog steeds een object kunnen maken met het new
-trefwoord, maar je krijgt een verouderingswaarschuwing.
Naast String
en wrappers, zijn er ook andere nuttige ingebouwde referentietypes, die je kunt vinden in de samenvatting van het pakket java.lang. Om enkele van deze meer geavanceerde referentietypes volledig te begrijpen, is aanvullende uitleg of voorkennis vereist. Daarom zullen we enkele ervan behandelen in onze volgende tutorials uit de Java-serie.
Literals
Literals vertegenwoordigen vaste waarden die direct in de code kunnen worden gebruikt en dus zowel aan primitieve als aan referentietypes kunnen worden toegewezen. Er zijn een paar soorten literals, die als volgt kunnen worden gecategoriseerd.
Primitieve Type Literals
Je hebt al een paar literals gebruikt in de sectie over primitieve types. Voor elk primitief type is er een literal, zoals die uit onze voorbeelden: 42
, 'a'
, en true
. Gehele getallen zoals 42
zijn gehele literals. Op dezelfde manier zijn karakters zoals 'a'
karakter literals, en true
en false
zijn booleaanse literals.
Primitive typen literals kunnen ook worden gebruikt om waarden te creëren voor referentietypen. De int
literal werd gebruikt bij het creëren van een Integer
object met de code Integer.valueOf(42)
. Er is ook een verkorte notatie voor dat, en je kunt de waarde rechtstreeks toewijzen zoals dit:
Integer theAnswer = 42;
42
is een integer literal, net als elk geheel getal, en je kunt het rechtstreeks toewijzen aan de variabele theAnswer
zonder enige extra statements. Het is gebruikelijk om een Integer
op deze manier te declareren omdat het handig is.
Deze verkorte benadering werkt ook voor andere primitieve typen literals en hun tegenhangers referentietypen zoals Boolean
, bijvoorbeeld:
Boolean isFun = true;
true
is de literal, die direct wordt toegewezen aan de variabele isFun
van het type Boolean
. Er is ook een false
literal, die je op dezelfde manier kunt toewijzen.
De String Literal
Er is ook een speciale literal voor het String
referentietype, en het wordt herkend door de dubbele aanhalingstekens rond de waarde. In dit voorbeeld is het "Hello, World!"
:
String helloWorld = "Hello, World!";
Het gebruik van literals is eenvoudiger en korter, en daarom geven veel programmeurs er de voorkeur aan. Je kunt echter nog steeds een String
variabele declareren met een nieuw String
object, zoals je al hebt gedaan in het gedeelte voor referentietypen.
De Nulwaarde
Er is nog een belangrijke constante: null
, die de afwezigheid van een waarde of het niet-bestaan van een object vertegenwoordigt. Null
stelt je in staat om een verwijzingstype te maken en het te wijzen op null
in plaats van naar een object te wijzen. null
kan worden gebruikt voor alle verwijzingstypen, maar niet voor enig primitief type.
Er is één voorbehoud bij de null
constante: je kunt variabelen ermee declareren, maar je kunt deze variabelen niet gebruiken totdat je deze opnieuw toewijst aan een geschikte, niet-nul waarde. Als je probeert een verwijzingstype variabele te gebruiken met een null
waarde, krijg je een foutmelding. Hier is een voorbeeld:
- String initiallyNullString = null;
- System.out.println("The class name is: " + initiallyNullString.getClass());
Als je deze code probeert uit te voeren in jshell
, zie je een fout vergelijkbaar met de volgende:
OutputinitiallyNullString ==> null
| Exception java.lang.NullPointerException
| at (#4:1)
Afhankelijk van je besturingssysteem en Java-versie kan je uitvoer verschillen.
De fout java.lang.NullPointerException
wordt gegenereerd omdat je probeert de String
methode getClass()
(die de naam van de klasse retourneert) aan te roepen op de variabele initiallyNullString
(die naar een null-object wijst).
Let op: Voor eenvoud noemen we java.lang.NullPointerException
een fout, ook al is het technisch gezien een uitzondering. Voor meer informatie over uitzonderingen en fouten, bekijk de tutorial, Exception Handling in Java.
Om de fout aan te pakken, moet je de waarde van initiallyNullString
opnieuw toewijzen zoals dit:
- String initiallyNullString = null;
- initiallyNullString = "not null any longer";
- System.out.println("The class name is: " + initiallyNullString.getClass());
De nieuwe, verbeterde code zal de volgende uitvoer weergeven:
OutputinitiallyNullString ==> null
initiallyNullString ==> "not null any longer"
The class name is: class java.lang.String
De bovenstaande uitvoer laat zien hoe initiallyNullString
eerst null
is, dan wordt het een nieuw String
-object dat "niet langer null"
bevat. Vervolgens, wanneer de methode getClass()
wordt aangeroepen op het geïnstantieerde object, krijg je java.lang.String
, waarbij String
de klassenaam is en java.lang
zijn pakket. Ten slotte wordt een volledige, betekenisvolle boodschap afgedrukt: "De klassenaam is: class java.lang.String"
.
Zulke declaraties van null
-waarden zijn gebruikelijker voor verouderde code. Ze worden gebruikt om eerst een variabele te maken en later de echte waarde toe te kennen, meestal via een logica die de laatste bepaalt. Echter, sinds Java versie 8 is er een nieuw referentietype genaamd Optioneel, dat meer geschikt is voor gevallen waarin null
eerder is gebruikt.
Lokale Variabelen Type Inferentie
Tot nu toe heb je enkele van de gebruikelijke gegevenstypen in Java gebruikt om variabelen te definiëren. Echter, Java 10 introduceerde een nieuwe functie genaamd lokale variabelentype-inferentie, waarmee je het sleutelwoord var
kunt gebruiken voor een nieuwe variabele. Met deze functie zal Java automatisch (dat wil zeggen, automatisch raden) het gegevenstype afleiden uit de lokale context. Type-inferentie is controversieel omdat het in contrast staat met de eerder uitgelegde uitgebreidheid van het definiëren van variabelen. De voor- en nadelen van zo’n functie zijn betwistbaar, maar het feit is dat andere statisch getypeerde talen, zoals C++, type-inferentie ondersteunen.
In ieder geval kan type-inferentie het gebruik van gegevenstypen niet volledig vervangen omdat het alleen werkt met lokale variabelen, dat wil zeggen variabelen binnen een methode. Laten we een voorbeeld bekijken met var
:
- var hello = "Hello";
- System.out.println(hello);
Je declareert de variabele hello
met het sleutelwoord var
om Java aan te geven het gegevenstype te detecteren. Daarna druk je het af naar de console op de gebruikelijke manier om te bevestigen dat het zoals verwacht werkt:
Ouputhello ==> "Hello"
Hello
Dit voorbeeld zal werken zolang je Java-installatie (meer specifiek, de JDK) versie 10 of hoger is. Het sleutelwoord var
wordt niet ondersteund in oudere versies.
Het type-inferentieproces vindt plaats tijdens het compilatieproces, dat wil zeggen wanneer je de code compileert. Het compilatieproces zet de broncode om naar machinetaal en past verschillende optimalisaties toe, waaronder type-inferentie. Dit zorgt ervoor dat de juiste hoeveelheid systeemgeheugen beschikbaar is voor de geïnferieerde variabelen. Dus, de machinetaal die je uitvoert na het compileren is volledig geoptimaliseerd, alsof je handmatig alle datatypes hebt gespecificeerd.
In dit voorbeeld werkt het var
-sleutelwoord omdat de variabele lokaal is, en het var
-datatype werkt alleen met lokale variabelen. Lokale variabelen zijn gedefinieerd binnen methoden en zijn alleen toegankelijk binnen de methoden, daarom worden ze “lokaal” genoemd.
Om te laten zien dat var
alleen kan worden gebruikt voor lokale variabelen, probeer het buiten de hoofdmethode te plaatsen, zoals dit:
- public class Hello {
- var hello = "Hello";
- public static void main(String[] args) {
- // example code
- }
- }
Als je de bovenstaande code plakt in jshell
, krijg je de volgende foutmelding:
Output| Error:
| 'var' is not allowed here
| var hello = "Hello";
| ^-^
var
is daar niet toegestaan omdat hello
buiten een methode staat en het niet langer als lokaal wordt beschouwd. Dus, type-inferentie werkt niet voor niet-lokale variabelen omdat de context niet betrouwbaar kan worden gebruikt om het datatype te detecteren.
Hoewel het gebruik van var
uitdagend kan zijn en niet vereist is, zul je er waarschijnlijk mee te maken krijgen, dus het is handig om ervan op de hoogte te zijn.
Gereserveerde Sleutelwoorden
Bij het declareren van variabelen in Java is er nog een belangrijke regel om te kennen. Er zijn gereserveerde trefwoorden die je niet kunt gebruiken als variabelennamen. Bijvoorbeeld, je kunt geen primitief van het type int
declareren en het new
noemen zoals dit:
- int new = 1;
Als je dit voorbeeld probeert, zul je compilatiefouten krijgen omdat new
een gereserveerd trefwoord is.
Output| Error:
| '.class' expected
| int new = 1;
| ^
| Error:
| <identifier> expected
| int new = 1;
| ^
| Error:
| '(' or '[' expected
| int new = 1;
| ^
| Error:
| unexpected type
| required: value
| found: class
| int new = 1;
| ^--^
| Error:
| missing return statement
| int new = 1;
| ^----------^
Het trefwoord new
wordt gebruikt voor het maken van nieuwe objecten en Java verwacht het niet op deze positie. In de lijst met fouten in de vorige uitvoer, is het eerste deel het belangrijkst:
Output| Error:
| '.class' expected
| int new = 1;
| ^
De fout '.class' verwacht
betekent dat wanneer je het trefwoord new
gebruikt, Java verwacht dat er een klasse zal volgen. Op dit punt is Java niet in staat om de verklaring te interpreteren en volgen de rest van de fouten.
De rest van de gereserveerde trefwoorden, zoals abstract
, continue
, default
, for
, en break
, hebben ook specifieke betekenissen in Java en kunnen niet worden gebruikt als variabelennamen. De volledige lijst van gereserveerde trefwoorden is te vinden op de Java Language Keywords pagina. Zelfs als je niet alle gereserveerde trefwoorden kunt onthouden, kun je compilatiefouten gebruiken om het probleem te identificeren.
Conclusie
In deze tutorial heb je geleerd over primitieve en referentietypen in Java, wat een complex maar essentieel onderwerp is. Neem de tijd om ermee te oefenen en ga de voorbeelden meer dan eens door. Probeer enkele van de datatypen en waarden te wijzigen. Let op wanneer fouten worden gegenereerd en wanneer niet om een gevoel te ontwikkelen voor succesvolle uitvoering van de code.
Voor meer over Java, bekijk onze serie Hoe te coderen in Java.
Source:
https://www.digitalocean.com/community/tutorials/understanding-data-types-in-java