Klassensystem
- Klassenhierarchie
- Basis Typen
- Wertebereich
- Scala Basis-Typen vs. Java primitive Typen
- Literale
- Wertetypen (value classes)
Stand: 10. August 2019
Scala-Version: 2.13.0
Klassenhierarchie
Die nachfolgende Grafik gibt einen Überblick über die Scala - Klassenhierarchie 1.
Basis Typen
In Scala gibt es keine primitive Datentypen. Alle Typen sind
Objekte. In Scala gibt es jedoch Objekttypen, die den primitiven
Datentypen in Java zugeordnet werden können. Eine
Sonderstellung unter den Basis-Typen stellt der Typ String
dar,
der auch in Java ein Objekt ist.
Nachfolgend eine Auflistung der Basis Typen in Scala:
Die Typen Int, Long, Short, Byte und Char
werden als integrale
Typen bezeichnet. Die integralen Typen und die Typen Float und Double
werden als numerische Typen bezeichnet.
Wertebereich
Der Wertebereich der Basis Typen entspricht dem der entsprechenden primitiven Typen in Java. Die bei numerischen Typen angegebene Bytezahl entspricht dem darzustellenden Wertebereich. Da die Basistypen vollwertige Objekte sind, benötigen diese eine größere Anzahl Bytes um diese im Speicher abzulegen.
Wertebereich der numerischen Basistypen
Basistyp | Wertebereich | ||||
Byte | -128 | (-27) | bis | 127 | (27-1) |
Char | 0 | bis | 216-1 | ||
Short | -215 | bis | 215-1 | ||
Int | -231 | bis | 231-1 | ||
Long | -263 | bis | 263-1 | ||
Float | ±3.4028235E38 | ||||
Double | ±1.7976931348623157E308 |
Basistyp | Bytes |
Byte | 1 |
Char | 2 |
Short | 2 |
Int | 4 |
Long | 8 |
Float | 4 |
Double | 8 |
Wertebereich von String
und Boolean
Ein Boolean
kann die Werte true
oder false
annehmen. Ein String ist eine beliebig lange Sequenz von Elementen des Typs Char
.
Scala Basis-Typen vs. Java primitive Typen
Da Scala vollwertige Objekte anstatt der primitiven Typen in Java verwendet, lässt vermuten, dass ein Scala Programm langsamer abläuft als ein Java Programm. Dies ist in der Regel nicht der Fall. Scala greift, wo möglich, auf primitive Typen in den Klassen zurück, sodass der Objekt-Overhead sich nicht wesentlich auf die Ausführungsgeschwindigkeit eines Scala Programms auswirkt. Scala Programme sind in der Ablaufgeschwindigkeit vergleichbar zu entsprechenden Java Programmen.
Durchgeführte Geschwindigkeitsmessungen des Autors anhand von Berechnungsprogrammen zeigen, dass Scala Programme oft nur unwesentlich langsamer sind und zum Teil auch schneller als die entsprechenden Java Programme. Diese Beobachtung deckt sich mit Angaben anderer Quellen zu Scala.
Literale
Literale sind vordefinierte Konstanten für Basistypen. Literale können überall dort im Quelltext verwendet werden, wo Konstanten-Variablen im Quelltext eingesetzt werden können.
Boolean
Literale
Der Datentyp Boolean
kennt genau zwei Literale:
true
false
welche den Wahrheitswerten wahr und falsch entsprechen.
Char
(Character) Literale
Ein Char
Literal ist ein einzelnes, druckbares Unicode Zeichen
oder eine Escape Sequenz in einfachen Anführungszeichen. Für Unicode
Zeichen im Bereich von 0 bis 255 ist auch eine Angabe in oktal Form möglich.
Nachfolgend einige Beispiele für Char
Literale:
'A' | Das Zeichen A |
'\u0042' | Das Zeichen B als Unicode Escape Sequenz |
'\141' | Das Zeichen a als Oktal Escape Sequenz |
'\n' | Der Zeilenumbruch |
Gleitkomma Literale
Double
Literale
Ein Double
Literal besteht aus einer Reihe von Zahlen und mindestens
einem der folgenden Elemente:
- Einem Dezimalpunkt (.)
-
Dem Exponentialzeichen
E
odere
mit zusätzlicher Angabe des Exponenten zur Basis 10 -
Die Angabe von
D
oderd
zur Kennzeichnung desDouble
Literals
Nachfolgend einige Beispiele für Double
Literale:
123.45 .123 123E0 123d 123D 123.45E0d
Ein Literal in der Form 123.
sollte man nicht mehr verwenden. Nach aktuellem Stand (23. November 2011),
wird ein Literal, dass auf einem Punkt endet in der Version 2.10 von Scala als deprecated gekennzeichnet und
wird mit der Version 2.11 sogar nicht mehr al Double
Literal erkannt.
Float
Literale
Für Float
Literale gelten zunächst die gleichen Regeln wie
für Double
Literale mit der Erweiterung, dass bei einem
Float
Literal ein "f" oder ein "F" am Ende des
Literals angegeben werden muss. Da ein Float
Literal ein "f"
oder "F" am Ende aufweisen muss, ist bei einem Float
der
Dezimalpunkt optional.
Beispiele für Float
Literale sind:
123.45f .123F 123.f 123F 123E0f
Ganzzahl Literale
Int
Literale
In Scala unterscheiden wir wie in Java je nach Schreibweise 3 unterschiedliche Typen von Int
Literalen:
- Dezimale
Int
Literale - Hexadezimale
Int
Literale - Oktale
Int
Literale
Ein dezimaler Int
Literal besteht aus den Ziffern 0 bis 9 und dem Minuszeichen
"-" für negative Werte. In der Dezimalschreibweise
darf ein Int
Literal nicht mit "0" oder "-0" beginnen (siehe Oktalschreibweise / Hexadezimalschreibweise).
Nachfolgend einige Beispiele für Int
Literale in Dezimalschreibweise:
256 748 -4656 -43573
In der Oktalschreibweise beginnt ein Int
Literal mit "0" oder "-0"-
In dieser Schreibweise sind ein führendes Minuszeichen "-" und die Ziffern
0 bis 7 zur Bildung des Literals erlaubt. Nachfolgend einige Beispiele für Int
Literale in Oktalschreibweise:
0123 -0653 0333 04563
Um ein Int
Literal in Hexadezimal anzugeben, muss das Literal mit
"0x" oder "0X", mit einem optionalen "-" für negative
Werte, eingeleitet werden. Im Anschluss folgt der Wert des Literals in hexadezimaler Schreibweise,
wo zusätzlich zu den Ziffern 0 bis 9 noch die Buchstaben A bis F bzw. a bis f
zur Bildung des Literals herangezogen werden können. Nachfolgend einige Beispiele
für Int
Literale in hexadezimaler Schreibweise.
0x123 0xff -0x00ff -0X54ab 0xabcdef
Long
Literale
Für Long
Literale gelten dieselben Regeln wie für
Int
Literale. Dies gilt auch für die Angabe in Oktal-
bzw. Hexadezimalschreibweise.
Die Unterscheidung zu anderen Ganzzahl Literalen erfolgt durch
die Endung des Literals mit dem Buchstaben "l" oder
"L". Nachfolgend einige Beispiele für Long
Literale:
123l 123L 0x235L 0324l 0xffL
Byte
und Short
Literale
Für Byte Literale gelten im Grunde dieselben dieselben Bedingungen wie für
Int
Literale. Voraussetzung ist jedoch, dass Sie einen Wert im Wertebereich
des Basistypen darstellen und einer entsprechenden Variable zugewiesen werden.
Nachfolgend einige Beispiele für Byte
und Short
Literale:
val value1 : Short = 123 val value2 : Byte = 123 val value3 : Byte = 0xf val value4 : Short = 012
String
Literale
Ein String
Literal ist eine Sequenz von Char
- Zeichen in doppelten
Anführungszeichen. Beispiel für String
Literale sind:
"Ich"
"123"
"test"
Das Anführungszeichen, der Backslash bzw. ein beliebiges Unicodezeichen können in einem String durch einen Backslash maskiert werden.
Müssen in einem String
Literal eine Vielzahl von (direkt eingebbaren)
Zeichen maskiert werden, kann ein String
Literal in dreifachen, doppelten
Anführungszeichen gesetzt werden. Dies führt dazu, dass der Backslash nicht
zur Maskierung herangezogen wird und auch alle anderen Zeichen wie angegeben behandelt werden.
Ein Beispiel für einen derartigen String
Literal ist:
"""\"1'\"""
welches der Zeichenkette
\"1'\
entspricht.
Wertetypen (value classes)
Scala kennt 9 eingebaute Wertetypen (value classes):
Int
Long
Short
Byte
Float
Double
Char
Boolean
Unit
Wertetypen sind in Scala vom Typ AnyVal
abgeleitet. Wertetypen
können in Scala nicht als Basisklasse für eigene Erweiterungen verwendet werden.
Seit Scala 2.10 ist es jedoch möglich, eigene Klassen von AnyVal
abzuleiten. Alle Klassen, die nicht zu den Wertetypen gehören, sind Referenztypen und
haben die gemeinsame Basisklasse AnyRef
.
Mit Ausnahme von Unit
entsprechen die Wertetypen den primitiven Datentypen von Java.
Der Datentyp Unit
kann mit dem Typ void
aus Java verglichen werden.
Der Typ Unit
wird häufig als Rückgabetyp von Methoden eingesetzt,
welche nur wegen ihrer Seiteneffekte aufgerufen werden und kein eigentliches Ergebnis
als Rückgabewert liefern.
Stellen wir uns nun der Frage, warum wir eine Unterscheidung zwischen Wertetypen und Referenztypen vornehmen. Die Arbeit mit primitiven Datentypen kann innerhalb der JVM sehr effizient geschehen. Es ist nicht notwendig Objekte zu erzeugen (zu verwalten) um mit primitiven Datentypen etwa Berechnungen durchzuführen. Würden wir in Scala immer mit den vollständigen Objekten arbeiten hätten wir einen gewaltigen Performance Nachteil gegenüber Java. Wie schon angedeutet ist dies nicht der Fall. Wo immer es möglich ist, arbeitetet die JVM bei Wertetypen mit primitiven Datentypen statt der vollwertigen Objekten. Ein "boxing" bzw. "unboxing"2 findet nur dann statt, wenn Objektfunktionalität benötigt wird, welche über die Eigenschaften der primitiven Datentypen hinausgeht.
1 Vergleiche [SQ4]
2 Als boxing / unboxing beschreibt man die Umwandlung eines primitiven Datentyps in ein Objekt bzw. die Umwandlung von einem Objekt in einen primitiven Datentyp.