Dieses Kapitel fasst die fundamentalen Klassen Object, String, StringBuilder, DateTime und TimeSpan zusammen und geht auf Besonderheiten ein, die nützlich für fortgeschrittene Programmierung sind.
10 Einige Basisklassen
10.1 Object 

Diese Klasse ist als Wurzel der Klassenhierarchie die einzige, die von keiner anderen Klasse abgeleitet ist. Wenn Sie keine explizite Elternklasse angeben, fügt der Compiler implizit Object ein. Die Funktionalität dieses gemeinsamen Vorfahrs teilen alle Objekte.
10.1.1 Methoden 

Sieben Methoden vererbt die Klasse Object an Subklassen: fünf öffentliche und zwei, die mit Protected auf Nachfahren beschränkt sind (siehe Tabelle 10.1).
Methode | Beschreibung | |
New |
Parameterloser Konstruktor |
|
Equals |
Gibt an, ob das gegebene Objekt diesem gleich ist. |
O |
Finalize |
Aufgerufen bei Zerstörung des Objekts (z. B. Ressourcenfreigabe) |
P |
GetHashCode |
Objektspezifischer Identifizierer (nicht garantiert eindeutig) |
O |
GetType |
Eine Type-Instanz, die den Typ des Objekts beschreibt |
|
MemberwiseClone |
Dupliziert die aktuelle Instanz und liefert die Referenz der Kopie. |
P |
ReferenceEquals |
Gibt an, ob die beiden Referenzen auf dasselbe Objekt zeigen. |
S |
ToString |
Liefert den vollqualifizierenden Namen einer Klasse. |
O |
Hinweis |
Wenn Equals Objekte inhaltlich vergleichen soll, muss die zugrunde liegende Klasse die Methode Equals neu definieren (siehe Abschnitt 3.14.5, »Equals«) oder den Gleichheitsoperator = überladen (siehe Abschnitt 3.11.3, »Vergleich«). |
Den Nutzen der Methode ToString habe ich bereits in Abschnitt 3.14.6, »ToString«, angedeutet. Hier möchte ich nur noch auf das Standardverhalten hinweisen, das den vollqualifizierten Klassennamen liefert, ohne Objekte derselben Klasse zu unterscheiden. Viele Klassen überschreiben das Verhalten, zum Beispiel Zahlenprimitive wie Double und Zeichenketten.
Public Overridable Function ToString() As String |
Finalize wurde bereits in Abschnitt 3.16.2, »Destruktoren«, gezeigt. Die anderen Methoden werden in den folgenden Abschnitten behandelt.
10.1.2 GetType 

Zur Laufzeit liegen für jeden Datentyp Metainformationen vor, die in einem Type-Objekt gespeichert sind.
Public Function [GetType]() As Type |
Um den Rahmen dieses Kapitels nicht zu sprengen, zeigt das folgende Beispiel nur eine ganz einfache Typanalyse. Mit den Klassen im Namensraum System.Reflection können Sie zur Laufzeit mit etwas Aufwand sogar neue Datentypen erzeugen.
'...\Basisklassen\KlasseObject\GetType.vb |
Option Strict On
Namespace Basisklassen
Class Kind
Public Feld As Integer = 9
End Class
Class Enkel : Inherits Kind : End Class
Module [GetType]
Private Sub Eltern(ByVal type As Type)
If type IsNot GetType(Object) Then Eltern(type.BaseType)
Console.Write(type.Name & " ")
End Sub
Sub Test()
Dim kind As New Enkel()
Dim kindertyp As Type = kind.GetType()
Console.WriteLine(kindertyp.Assembly.FullName)
Eltern(kindertyp)
For Each fi As System.Reflection.FieldInfo In kindertyp.GetFields()
Console.Write(fi.Name & "=" & fi.GetValue(kind).ToString())
Next
Console.ReadLine()
End Sub
End Module
End Namespace
10.1.3 Gleichheit 

Wie in Abschnitt 3.1.9, »Datentypen«, bereits erläutert wurde, muss bei Gleichheit von Objekten zwischen Objektreferenzen auf identische Objekte und Objekten mit gleichen (oder sogar denselben) Werten unterschieden werden. Sowohl Equals als auch ReferenceEquals in der Klasse Object verstehen unter Gleichheit die Identität zweier Referenzen. Für einen inhaltlichen Vergleich muss die Methode Equals in einer Kindklasse überschrieben werden.
Public Overridable Function Equals(obj As Object) As Boolean |
Hinweis |
Auch wenn die Methode Equals der Schnittstelle IEquatable(Of T) als typsicher bevorzugt werden sollte, kann sie die Methode in Object nicht ersetzen, sondern nur ergänzen. |
Was Sie als »gleich« ansehen, bleibt Ihnen überlassen. In der Regel werden die Werte der Felder herangezogen. Im folgenden Beispiel hat die Klasse Ball keine Felder, und verschiedene Bälle werden nicht unterschieden; Equals gibt True zurück. So hält der Torwart einen Ball und nicht den Ball. Bitte beachten Sie den Test auf eine Nullreferenz und korrekten Typ in der Methode Equals, die als Parametertyp immer Object hat.
'...\Basisklassen\KlasseObject\Feldgleichheit.vb |
Option Strict On
Namespace Basisklassen
Module Feldgleichheit
Class Ball
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If obj Is Nothing OrElse Not TypeOf obj Is Ball Then Return False
Return True
End Function
End Class
Class Spieler
Friend ball As Ball
End Class
Sub Test()
Dim regulär As New Ball(), zuviel As New Ball()
Dim stürmer As New Spieler : stürmer.ball = regulär
Dim torwart As New Spieler : torwart.ball = zuviel
Console.WriteLine("Stürmerball ähnelt Torwartball: {0}", _
stürmer.ball.Equals(torwart.ball))
Console.WriteLine("Stürmerball ist Torwartball: {0}", _
Object.ReferenceEquals(stürmer.ball, torwart.ball))
Console.ReadLine()
End Sub
End Module
End Namespace
Der Schiedsrichter wird sich wohl auf den zweiten Vergleich stützen.
Stürmerball ähnelt Torwartball: True
Stürmerball ist Torwartball: False
Nicht immer wird die Methode Equals zur Definition von Gleichheit herangezogen. Viele Funktionen nutzen aus Effizienzgründen die Methode GetHashCode, zum Beispiel einige der Auflistungen:
Public Overridable Function GetHashCode() As Integer |
Wenn Sie Ihren Klassen eine eigene Vorstellung von Gleichheit mitgeben wollen, gilt daher:
Equals() und GetHashCode() sollten immer gemeinsam überschrieben werden. |
Das folgende Beispiel weist auf das Problem hin. Obwohl die verwendete Auflistung GetHashCode zur Sortierung benutzt, müssen beide Methoden in Ware überschrieben werden. Wird nur eine weggelassen, wird das Objekt nach der Änderung nicht mehr gefunden.
'...\Basisklassen\KlasseObject\Boxing.vb |
Option Strict On
Namespace Basisklassen
Module Boxing
Structure Ware
Public Menge, Preis As Double
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If obj Is Nothing OrElse Not TypeOf obj Is Ware Then Return False
Return CType(obj, Ware).Preis.Equals(Preis)
End Function
Public Overrides Function GetHashCode() As Integer
Return Preis.GetHashCode()
End Function
End Structure
Sub Test()
Dim waren As New HashSet(Of Ware)
Dim mehl As New Ware() : mehl.Preis = 0.52 : waren.Add(mehl)
Console.WriteLine("Mehl gefunden: {0}", waren.Contains(mehl))
mehl.Menge = 0.54
Console.WriteLine("Mehl gefunden: {0}", waren.Contains(mehl))
Console.ReadLine()
End Sub
End Module
End Namespace
Der Compiler sucht sich für einen Methodenaufruf immer den am besten passenden Typ heraus. Aus diesem Grund wurde die Schnittstelle IEquatable(Of T) geschaffen. Sie stellt das typisierte Pendant zu Equals() dar. Diese Möglichkeit entbindet Sie aber nicht von der Notwendigkeit, auch die allgemeine Equals()-Methode zu definieren (und damit auch GetHashCode()), denn nicht in jeder Situation hat der Compiler genügend Informationen, um die am besten passende Methode zu wählen.
10.1.4 Objekte kopieren 

Die Methode MemberwiseClone kopiert ein vorhandenes Objekt und liefert die Referenz auf die Kopie:
Protected Function MemberwiseClone() As Object |
Von allen Feldern wird eine sogenannte flache Kopie erzeugt. Speichert ein Feld eine Objektreferenz, wird die Referenz als solche kopiert, nicht aber das Objekt, auf das sie zeigt. Durch den Zugriffsmodifizierer können Sie die Methode nicht von außerhalb der Klassenhierarchie aufrufen. Für diesen Zweck gibt es die Schnittstelle ICloneable.
Public Interface ICloneable |
Damit lässt sich nun einfach eine Kopierfunktion erstellen. Das folgende Beispiel nutzt MemberwiseClone, um eine flache Kopie zu erzeugen. Innerhalb von Clone wird für das Feld Clone aufgerufen, um eine tiefe Kopie zu erzeugen:
'...\Basisklassen\KlasseObject\Kopie.vb |
Option Strict On
Namespace Basisklassen
Module Kopie
Class Gemälde : Implements ICloneable
Public Wert As Single = Rnd()
Public Function Clone() As Object Implements ICloneable.Clone
Return Me.MemberwiseClone()
End Function
End Class
Class Fälscher : Implements ICloneable
Public obj As New Gemälde()
Public Function Clone() As Object Implements ICloneable.Clone
Dim kopie As Fälscher = CType(Me.MemberwiseClone(), Fälscher)
kopie.obj = CType(obj.Clone(), Gemälde)
Return kopie
End Function
End Class
Sub Test()
Dim meister As New Fälscher()
Dim stift As Fälscher = CType(meister.Clone(), Fälscher)
Console.WriteLine("Selben Fälscher {0}", meister Is stift)
Console.WriteLine("Selben Gemälde {0}", meister.obj Is stift.obj)
Console.WriteLine("Selben Werte {0}", meister.obj.Wert = stift.obj.Wert)
Console.ReadLine()
End Sub
End Module
End Namespace
Hinweis |
Wenn Feldvariablen Arrays speichern, müssen diese für eine tiefe Kopie erst kopiert werden, bevor die Einzelelemente geklont werden. |
Die Ausgabe zeigt, dass eine tiefe Kopie erzeugt wurde:
Selben Fälscher False
Selben Gemälde False
Selben Werte True
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.