Markus Nestvogel - Institut für Wirtschaftsinformatik

Werbung
Westfälische Wilhelms-Universität Münster
Ausarbeitung
C#
(Im Rahmen des Seminars – Programmiersprachen)
Markus Nestvogel
Themensteller: Prof. Dr. Herbert Kuchen
Betreuer: Roger Müller
Institut für Wirtschaftsinformatik
Praktische Informatik in der Wirtschaft
Inhaltsverzeichnis
1 Einleitung........................................................................................................................1
2 Microsofts .NET............................................................................................................. 1
2.1 Das .Net Framework............................................................................................... 2
2.1.1 Intermediate Language...................................................................................... 2
2.1.2 Common Type System...................................................................................... 4
2.1.3 Werttypen.......................................................................................................... 5
2.1.4 Verweistypen..................................................................................................... 6
2.1.5 Common Language Specification......................................................................7
2.2 Framework Class Library (FCL).............................................................................9
2.3 Common Language Runtime (CLR).......................................................................9
2.3.1 Typverwaltung und Assemblies........................................................................ 9
2.3.2 Codeverwaltung...............................................................................................11
3 C#..................................................................................................................................12
3.1 Klassen und Vererbung.........................................................................................13
3.2 Grundsätzlicher Aufbau........................................................................................ 15
3.3 Eigenschaften........................................................................................................16
3.4 Ereignisbehandlung und Delegaten...................................................................... 16
3.5 Quicksort...............................................................................................................17
4 Fazit.............................................................................................................................. 19
5 Literaturverzeichnis...................................................................................................... 20
6 Anhang..........................................................................................................................22
6.1 Quicksort in C#.....................................................................................................22
6.2 Quicksort in Java.................................................................................................. 24
II
1 Einleitung
1 Einleitung
Im Juni 2000 stellte Microsoft erstmals C# als eigens auf .NET abgestimmte
objektorientierte Programmiersprache der Öffentlichkeit vor und veröffentlichte gute 20
Monate später die finalen Versionen.
Die Ausarbeitung versucht einen Überblick über die Besonderheiten von C#,
insbesondere im Vergleich zu ihren direkten Verwandten C++ und Java, zu geben. Eine
Betrachtung von C# unabhängig von .NET ist kaum möglich und auch nicht ratsam.
Daher wird dieser Bereich im ersten Kapitel ausführlich besprochen.
Darauf folgend geht der Text auf C# als solches und insbesondere auf die auffälligsten
Neuerungen gegenüber anderen objektorientierten Programmiersprachen ein. Das zweite
Kapitel endet mit einem Vergleich von Implementierungen des Quicksort-Algorithmus
in C# und Java.
Abschließend wirft die Arbeit noch einen Blick auf die Aufgabenbereiche der Sprache
C# und versucht ihre Zukunftschancen zu bewerten.
2 Microsofts .NET
Microsoft
definiert
sich
und
seine
Unternehmensphilosophie
in
seinen
Pressemitteilungen wie folgt: empower people through great software - any time, any
place and on any device. [MS1]
Das im Juli 2000 vorgestellte .NET folgt diesem übergeordneten Unternehmensziel in
einer für Microsoft bisher für nicht möglich gehaltenen Konsequenz, es setzt sich die
„Verknüpfung von Informationen, Menschen, Systeme und Geräte“ zum Ziel [MS2].
Zur Verwirklichung dieser Strategie richtet Microsoft seine gesamte Unternehmenspolitik auf .NET ab, im folgenden interessieren wir uns aber nur für das .NET
Framework als technisches Fundament des Gesamtkonzeptes. Hinter dem groß
vermarkteten Schlagwort .NET steckt nämlich weitaus mehr als zur Besprechung von
C# nötig ist.
1
2 Microsofts .NET
2.1 Das .Net Framework
Das .NET Framework von Microsoft besteht im wesentlichen aus zwei Elementen; zum
einen ist eine Laufzeitumgebung namens Common Language Runtime (CLR) zu
nennen, zum anderen eine Basisklassenbibliothek namens Framework Class Library
(FCL). Diese zwei stellen Microsofts eigene Implementierung der ebenfalls im .NET
festgelegten Spezifikationen der Common Language Specification (CLS), der
Intermediate Language (IL) und des Common Type Systems (CTS) dar. Diese sind
Bestandteil der Common Language Infrastruktur (CLI), die von der European Computer
Manufactures Association [ECMA1] und der ISO [ISO1] standardisiert wurde. Dadurch
ist es möglich das viele verschiedene Programmiersprachen auf .NET aufsetzen können,
zur Zeit buhlen ca. 20 Sprachen um die Gunst des Programmierers [MS3]. Die
wichtigsten sind wohl C++ mit verwalteten Erweiterungen, VisualBasic.NET,
Delphi.NET,
das
Javaderivat
J#
und
natürlich
C#.
Auch
funktionale
Programmiersprachen wie Haskell finden ihren Weg nach .NET. Grundsätzlich ist es
möglich auch funktionale Sprachen in IL zu übersetzen, für eine noch bessere
Unterstützung veröffentlichte Microsoft aber eine erweiterte Version der IL, die ILX.
Dennoch bleibt der Code abwärtskompatibel zur IL [MSR].
Auch die .NET auf den Leib geschneiderte Sprache C# hat Microsoft bei der ECMA
[ECMA2] und der ISO [ISO2] standardisieren lassen. Hierdurch ist es prinzipiell jedem
möglich die gesamte .NET Umgebung auch auf andere Plattformen als Windows zu
portieren und so einen wichtigen Vorteil von Java auszugleichen. Für FreeBSD hat
Microsoft diese Aufgabe bereits selbst übernommen. Unter Linux ist für Mitte 2004
zum Beispiel das finale Release des Mono-Projektes geplant [MONO], die Entwickler
haben sich das ehrgeizige Ziel gesetzt nicht nur die CLI und C# zu implementieren,
sondern auch einen Großteil der FCL zu portieren. Ein weiteres Open Source Projekt
stellt dotGNU dar, als Besonderheit soll hier vorerst kein Just-In-Time Kompiler (siehe
2.3.2) sondern nur ein Interpreter für die Codeausführung sorgen [DG].
2
2 Microsofts .NET
2.1.1 Intermediate Language
Die meisten herkömmlichen Compiler liefern Maschinencode, der auf eine bestimmte
Prozessorarchitektur abgestimmt ist. .NET Compiler aber erzeugen Binärdateien
(Assemblies) mit Metadaten und einem Zwischencode namens Intermediate Language
(IL). Diese Assemblies können nicht direkt auf einem Prozessor ausgeführt werden,
stattdessen laufen sie innerhalb der CLR. Die IL kann man als eine Art höheren
Assemblercode ansehen, die Unterstützung objektorientierter Funktionalität wie etwa
die Ideen von Klassen, Kapselung und Verbergen von Daten und auch die Vererbung
sind fest in sie integriert. Dafür existieren in IL mehr als 220 Instruktionen [MS4], also
wesentlich mehr als bei x86 Assembler.
.locals init ([0] int32 int a = 2341;
a, [1] int32 b, int b = 2;
int c = a+b;
[2] int32 c)
IL_0000:
IL_0005:
IL_0006:
IL_0007:
IL_0008:
IL_0009:
IL_000a:
IL_000b:
ldc.i4 0x925
stloc.0
ldc.i4.2
stloc.1
ldloc.0
ldloc.1
add
stloc.2
0 sipush 2341
3 istore_1
4 iconst_2
5 istore_2
6 iload_1
7 iload_2
8 iadd
9 istore_3
10 return
Abbildung 1 Addition zweier Integer in IL und Java Bytecode
Entgegen dem Assembler Code werden lokale Variablen in der CLR nicht auf dem
Stack geladen, stattdessen liegen sie im Speicher. Erst durch einen Methodenaufruf
werden Werte durch Ladebefehle vom Typ ld aus dem Speicher in den Stack geladen.
Hat die Methode ihre Arbeit vollendet, werden die Werte aus dem Stack durch
Speicherbefehle vom Typ st wieder in den Speicher geschrieben. Hier werden die
Werte von einem Methodenaufruf zum nächsten gespeichert.
Anders als im Java Bytecode sind die Typinformationen der einzelnen Argumente
meistens nicht Teil der Instruktionen, sondern werden von dem Just In Time Compiler
aus dem Stackinhalt bestimmt. Dadurch wird ganz im Sinne der Sprachunabhängigkeit
3
2 Microsofts .NET
der Compilerbau erleichtert und die Typbestimmung der CLR überlassen. Da dies einen
Interpreter sehr verlangsamen würde, verzichtet Microsofts .NET, im Gegensatz zu
Java, auf die Möglichkeit des Interpretierens, also des Zeilenweisen Ablaufen des
Codes.
Ebenso wie Sun für seinen Bytecode stellt auch Microsoft für die IL ein Tool
(ildasm.exe) zur Anzeige des Codes zur Verfügung, so kann man die Typdefinitionen
und Namen von Methoden in schlecht oder gar nicht kommentierten Klassen
herausfinden und leichter in eigenen Code weiterverwenden. Allerdings steigt so auch
die Gefahr, dass Code geklaut werden kann und unrechtmäßig in fremden Programmen
wiederverwendet wird. Programme wie der Salamander .NET Decompiler [SAL]
können IL sogar komplett in Hochsprache zurückübersetzen. Durch Verschlüsselung
können aber zumindest die Methoden- und Variablennamen unkenntlich gemacht
werden.
2.1.2 Common Type System
Normalerweise ist das Typsystem in den Compiler einer Sprache integriert; in .NET
wandert es aber als Common Type System (CTS) in die CLR und steht daher allen
darauf ablaufenden Sprachen zumindest grundsätzlich zur Verfügung. Dadurch gibt es
keine verschiedenen Typdefinitionen mehr. So ist zum Beispiel der Datentyp short in
C# und in VB.NET nicht nur per Definition gleich, tatsächlich benutzen beide Sprachen
sogar dieselbe Implementierung dieses Typs.
Typen, die innerhalb des CTS definiert sind, werden als verwaltete Typen (managed
Types) bezeichnet, außerdem ist es möglich nicht verwaltete Typen zu verwenden, dann
ist der Code aber weder sprachübergreifend einsetzbar noch ist die Typsicherheit
innerhalb der CLR gesichert.
Da alle Datentypen (Klassen) in IL vorliegen, wird eigener Quellcode nach Übersetzung
automatisch selbst Teil des CTS und steht ebenfalls allen auf .NET aufsetzenden
Sprachen zur Verfügung.
4
2 Microsofts .NET
Datentyp (System.Object)
Werttypen (System.ValueType)
In die Sprache integrierte Werttypen (int, bool etc.)
.NET-Werttypen (System.Int32,Point, Recangel etc.)
benutzerdefinierte Werttypen (struct)
Aufzählungsrypen (System.Enum)
.NET-Aufzählungstypen (System.Int32, etc.)
benutzerdefinierte Aufzählungstypen (enum)
Verweistypen
deklarierte Datentypen
.NET-Schnittstellen (System.IFormtable etc.)
benutzerdefinierte Schnittstellen (interface)
benutzerdefinierte Zeigertypen (*-Operator; unsafe)
Quelle: c’t 15/03 S. 212
implementierte Datentypen
Arrays (System.Array)
Delegaten (Funktionszeigerprotot.; System.Delegate)
.NET-Delegaten (System.EventHandler etc.)
benutzerdefinierte Delegaten (delegate, event)
Klassen
Boxing-Klassen (als Verweistypen verpackte Werttypen)
.NET-Klassenhierarchie (für Einzelsprache sichtbar)
benutzerdefinierte Klassen (class)
systematische Kategorie
.NET-Kategorie
Benutzerdef. C#-Kategorie
Abbildung 2 Das CTS aus der Sicht von C#
Wie in Abbildung 2 zu sehen, sind alle Datentypen direkte beziehungsweise indirekte
Ableitungen des „Urdatentyps“ System.Object. Also werden auch elementare
Datentypen wie Integer als Klasse und ihre Werte als Objekte gehandhabt. Im
Gegensatz zu den verbreitetsten objektorientierten Programmiersprachen ist dies ist
etwas absolut neuartiges. Selbst in Java sind die primitiven Datentypen keine Klassen
im Objektorientierten Sinn, denn sie besitzen weder Eigenschaften noch Methoden
[C#K02, S.116]. Dort werden diese erst durch den Einsatz von Wrapper-Klassen
bereitgestellt. Um die Performance möglichst hoch zu halten, sind die Klassen aber auch
innerhalb .NET fest implementiert und mit dem Modifizierer sealed versehen, das heißt,
sie können nicht für eigene Ableitungen verwendet werden, wohl aber beinhalten sie
Methoden.
Durch diese konsequente Umsetzung des objektorientierten Gedankens gibt es auf
erster Ebene nur genau zwei Arten von Typen, Werttypen und Verweistypen.
2.1.3 Werttypen
Wie es der Name schon sagt, repräsentieren Werttypen echte Werte. Hierzu gehören
neben den elementaren Datentypen wie int, short oder double auch komplexe Werttypen
5
2 Microsofts .NET
wie Aufzählungstypen (enums) und Strukturen (structs). Besonders auffallend ist der
von Microsoft aus Visual Basic übernommene Typ decimal. Dieser eignet sich
insbesondere für finanzmathematische Berechnungen, da er bis auf die 28.
Dezimalstelle exakt berechnet. Dies wird durch eine 128-Bit-Repräsentation des
Wertebereichs ±1,0 * 10-28 bis ±7,9 * 10-28 erreicht.
Werttypen werden auf dem so genannten Evaluation Stack der CLR gespeichert und
verbleiben dort bis zum Ende ihres Geltungsbereichs, also ihres Methodenaufrufs.
Danach wird der Evaluation Stack wieder geleert.
2.1.4 Verweistypen
Man kann Verweistypen auch als objektorientierte Zeiger verstehen. Bei der Definition
einer Variablen eines Verweistyps, wird ein neues Objekt im Heap Speicher der CLR
angelegt, das später mit Variablen gefüllt wird. Im Stack wird lediglich ein Verweis auf
den zum Objekt gehörenden Speicherbereich im Heap abgelegt. In C# bemerkt man den
Unterschied
zwischen
Wert-
und
Verweistypen
an
der
Wirkung
des
Zuweisungsoperators >>=<<. Einem Verweistyp wird ein weiterer Verweis auf ein- und
denselben Speicherbereich zugewiesen, wohingegen bei einem Werttypen eine weitere
Kopie des Wertes angelegt wird. Eine Ausnahme bilden hier die Strings, die zwar
Verweistypen sind, sich aber wie Werttypen verhalten. Dies geschieht, da der Stack
durch seine einfacheren Organisation dem Heap in Sachen Geschwindigkeit einiges
voraus ist.
Laut Definition sind sowohl Wert als auch Verweistypen Objekte, aber nur die
Verweistypen werden, wie bei Objekten üblich, auf dem Heap gespeichert.
Nun stellt sich die Frage wie ein Werttyp denn eine Objektmethode aufrufen kann. Dies
geschieht durch das so genannte Boxing und Unboxing. Ruft ein Werttyp eine
Objektmethode auf, wird von der CLR automatisch ein temporäres Objekt auf dem
Heap angelegt und der Inhalt des Werttyps dort hinein kopiert. Nach der Ausführung des
Methodenaufrufs wird das Objekt wieder gelöscht und die CLR arbeitet mit dem
Werttyp weiter. Möchte man das Arbeiten mit temporären Ojekten vermeiden, kann
man durch explizites Boxing Werttypen manuell in Verweistypen umwandeln. Den
6
2 Microsofts .NET
umgekehrten Effekt erreicht man durch manuelles Unboxing, wobei dieser Vorgang nur
für Objekte erlaubt ist, die durch Boxing erzeugt wurden. Objekte vordefinierter oder
selbst definierter Klassen können nicht in Werttypen umgewandelt werden.[C#21]
// implizites Boxing
string s = 7.GetType().ToString();
i
123
// explizites Boxing
int i = 123;
object 0 = i;
int j = (int) o;
o
System.Int32
123
j
123
Quelle: Die .NET CLR, [MS5]
Abbildung 3 Boxing und Unboxing
Objekte werden in der Regel mit Hilfe des new-Operators erzeugt, ausgenommen
Strings, hier übernimmt der Compiler automatisch das Erzeugen eines Objektes. Sobald
es keine Verweise auf ein Objekt mehr gibt ist es unwiderruflich verloren. Damit der
Speicher nicht voll mit solchen „Objektleichen“ wird, durchläuft die automatische
Garbage Collection periodisch den Heap und entfernt alle Objekte für die kein Verweis
im Stack gefunden wird.
Innerhalb der Verweistypen fallen die Delegaten (delegates) ins Auge, da auf sie im
Kapitel 3 noch näher eingegangen wird, sei hier nur der Vollständigkeit halber erwähnt,
dass sie eine objektorientierte Version von Funktionszeigern darstellen.
2.1.5 Common Language Specification
.NET versucht die Grundlage von möglichst vielen verschiedenen Programmiersprachen
zu sein. Damit all diese Sprachen von der gemischtsprachigen Programmierung
7
2 Microsofts .NET
profitieren können, müssen sie auf ein gemeinsames Fundament aufbauen. Dieser wird
von Microsoft in Form der Common Language Specification (CLS) festgelegt.
Wie in 2.1.2 besprochen, spezifiziert das CTS die Typen, die in Programmen verwendet
werden dürfen, um auf der CLR zu laufen. Die CLS hingegen legt fest, wie das CTS
innerhalb der Sprachen verwendet werden muss um kompatiblen, sprachübergreifenden
Code zu erzeugen.
Laut der ersten Regel [ECMA – 335, S. 26] betrifft die CLS alle öffentlichen Teile
einer Typdefinition, wobei interne Teile sich nicht nach diesem Standard richten
müssen.
Im wesentlichen regelt die CLS die Menge der grundlegenden Datentypen und stellt
einige Regeln für die Namensgebung auf. So dürfen sich Namen nicht nur durch Großund Kleinschreibung unterscheiden, da nicht alle auf .NET aufsetzenden Sprachen
„Case Sensitive“ sind. Auch dürfen Methoden und Felder nicht die gleichen Namen
besitzen, wenn sie CLS kompatibel sein wollen.
Alle Regeln der CLS ergeben einen Kompatibilitätsstandard, der es ermöglicht, dass ein
in einer anderen Sprache implementierter Datentyp so benutzt werden kann, als ob er in
der eigenen geschrieben wäre. So wird erreicht, dass Programmteile aus verschiedenen
Sprachen aneinander Variablen übergeben können. Also handelt es sich bei CLSkonformen Datentypen um echte Basisklassen im Sinne der objektorientierten
Programmierung, die auf Wunsch auch abgeleitet werden können.
Dadurch
kann
.NET
allen
Sprachen
eine
umfangreiche
gemeinsame
Basisklassenbibliothek zur Verfügung stellen und muss sie nicht für jede einzelne
Sprache portieren.
Sprachen die jeden CLS kompatiblen Typen verarbeiten können, nennt man CLS Customer und solche, die jeden vorhandenen CLS – konformen Typen erweitern
können, nennt man CLS – Extender. C# ist, als Haus und Hof Sprache des .NET
Systems, sowohl Consumer als auch Extender.
8
2 Microsofts .NET
2.2 Framework Class Library (FCL)
Die FCL stellt die Basisklassenbibliothek des .NET Frameworks dar, ihre über 2500
Klassen bieten dem Entwickler einen reichhaltigen Fundus an grundlegenden
Komponenten als Ausgangspunkt für eigene Programme. Im wesentlichen ermöglichen
die Klassen den objektorientierten Zugriff auf die Funktionen des unter dem .NET
Framework liegenden Betriebssystems. Insbesondere unter Microsofts eigenem
Betriebssystem Windows scheint die FCL den Java Foundation Classes überlegen, da
sie sich eng an die verbreiteten Windows Standards hält. Dies erlaubt dem Entwickler
zum Beispiel ein leichtes verwenden von standardisierten Layouts.
2.3 Common Language Runtime (CLR)
Die CLR ist für die eigentliche Ausführung des in IL vorliegenden Codes zuständig.
Dazu obliegen ihr mehrere Aufgabenbereiche.
Marshalling
(Inter-Prozesskommunikation)
COM-Interop
API-Anbindung
Prozessraumverwaltung
Application Domains
Freispeicherverwaltung
Garbage Collection
Common Language Runtime (CLR)
Codeverwaltung
Quelle: C# Kompendium S. 42
Typverwaltung
Namensbereiche
Ausführungskontrolle
Gemeinsam genutzte
Assemblies
(Global Assembly Cache)
Typsicherheit
private
Assemblies
Assembly-Loader
Codesicherheit
JIT
Manifest
Abbildung 4 Aufgaben der CLR
2.3.1 Typverwaltung und Assemblies
Ein Ziel von .NET ist die Abschaffung der in der klassischen Windowswelt nötigen
Registrierung und der damit verbundenen „dll-Hölle“.
9
2 Microsofts .NET
Die .NET Typverwaltung muss sich daher anders die Informationen über
Codekomponenten verschaffen und selbstständig verwalten.
Aus diesem Grund ist ein Blick auf die durch einen Compiler erzeugten Assemblies
notwendig. Veranlasst man einen Compiler Quellcode in die IL zu übersetzen, so erhält
man, falls eine Main() Methode vorhanden ist, eine .exe – Datei, fehlt diese, erhält man
eine reine Klassenbibliothek mit der Dateierweiterung .dll. Beide haben zwar vertraute
Namen, sind aber ohne installiertes .NET Framework nicht ausführbar.
In
einem
Assembly
ist
neben
dem
reinen
Codeabschnitt
zusätzlich
ein
Ressourcenabschnitt, in dem Verweise auf andere Ressourcen wie Bilder, Dokumente
und andere Klassen gespeichert werden, enthalten. Für die Typverwaltung interessanter
ist aber das so genannte Manifest; es besteht aus Metadaten, die Informationen über die
öffentlich zur Verfügung stehenden Typen, die Ressourcen- und Datendateien
beinhalten.
Ferner
offerieren
sie
Versionsinformationen,
ggf.
zusätzlichen
Informationen zum Autor und Copyright Bestimmungen und auch Informationen zur
Verschlüsselung können Bestandteil sein.
Möchte man ein Assembly auch anderen zugänglich machen, kann man es beim Global
Assembly Cache (GAC) anmelden, standardmäßig sind Assemblies aber privat.
Wird nun auf ein Assembly verwiesen, sucht die Typverwaltung zunächst im privaten
Bereich der Anwendung, wird sie dort nicht fündig, so wird im GAC gesucht. Dort
können nun, im Gegensatz zur klassischen .dll Registrierung, mehrere Versionen eines
Assembly parallel existieren, da ja die benötigte Versionsnummer in den Metadaten
gespeichert wird. Böse Überraschungen, dass Programme nach der Installation eines
neuen nicht mehr funktionieren, sollten so der Vergangenheit angehören.
In Java mussten bisher Deployment Deskriptoren erstellt werden, um Anwendungen
während der Laufzeit mit Informationen zu versorgen. Ab der für Mitte 2004
angekündigten Java-Version 1.5 soll aber ein näher an .NET orientiertes Gerüst für die
Metadaten eingeführt werden [CW].
Für den Entwickler ist dann der augenfälligste Unterschied, dass in einem Assembly, im
Gegensatz zu einem Java Class File, mehrere Klassen gespeichert werden können.
10
2 Microsofts .NET
2.3.2 Codeverwaltung
JIT – Kompilierung
Die Assemblies liegen in IL vor und weil .NET auf einen Interpreter verzichtet, muss
der Code zur Ausführung in nativen Maschinencode übersetzt werden. Diese Aufgabe
übernimmt der in die CLR eingebettete JIT-Compiler, der während der Laufzeit den
benötigten Codeabschnitt methodendweise übersetzt. Der übersetzte Code wird nach
Verwendung im Cache zwischengespeichert, so dass häufig benutzte Methoden nicht
ständig erneut kompiliert werden müssen.
Bei Installation eines Assemblies in den GAC läuft der JIT-Compiler einmalig ab,
gespeichert wird dann der optimierte Maschinencode.
Application Domains
Normalerweise isoliert das Betriebssystem parallel ablaufende Anwendungen in
verschiedenen Prozessen, die alle über einen eigenen Adressraum verfügen, so dass sie
sich nicht gegenseitig stören. Das Erzeugen der Prozesse, sowie ein ProgrammcodeAufruf zwischen ihnen und dem damit verbundenen „Marshalling“, ist sehr
zeitaufwendig.
Mit dem .NET Framework führt Microsoft das Konzept der Application Domains ein.
Es sieht vor, dass sich mehrere Anwendungen einen einzigen Prozessraum teilen und
darin als Thread ausgeführt werden. Dies hat den Vorteil, dass die Erzeugung einer
Application Domain schneller erfolgt als das Erzeugen eines Prozesses. Auch ein
Programmcode-Aufruf zwischen ihnen läuft schneller als zwischen Prozessen ab.
Computer
Prozess
Prozess
Verwaltete Umgebung
Freispeicherverwaltung, Typsicherheit auf Basis von
Laufzeittypen, Codesicherheit, Lizensierung
Application Domain
Anwendung
Unverwaltete
Umgebung
Application Domain
Anwendung
Anwendung
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Direkter
Speicherzugriff
möglich, COM –
Komponenten,
Bibliotheken mit APIRoutinen
Abbildung 5 Application Domains in verwalteter Umgebung
11
2 Microsofts .NET
Um dieses Konzept durchführen zu können und um vor ungewollter oder böswilliger
gewollter Störung zu schützen, muss der beteiligte Code typsicher sein. Der Code, der
diese Bedingung erfüllt, wird verwalteter (managed) Code genannt. Im Gegensatz dazu
steht der nicht verwaltete (unmanaged) Code, er wird wie bisher in externen Prozessen
ausgeführt. Auf diese Weise können bisherige Bibliotheken auch ohne eine Portierung
nach .NET weiter verwendet werden. C# Code ist grundsätzlich typsicher, ansonsten
muss er explizit als „unsafe“ deklariert werden und der Compiler vor dem
Übersetzungsvorgang in IL davon in Kenntnis gesetzt werden. Durch ein solches
Vorgehen kann man sogar aus .NET heraus direkt auf den physischen Speicher
zugreifen und beispielsweise sehr hardwarenah programmieren. Geschieht dies aber bei
verteilten Anwendungen, so können solche nur von Benutzern mit Administratorrechten
für das jeweilige Netzwerk ausgeführt werden.
3 C#
Um die Funktionen des .NET Frameworks vollständig ausreizen zu können, hätte aller
Sprachunabhängigkeit zum Trotz, jede bisherige Sprache mehr oder weniger stark
verändert werden müssen. Aus diesem Grund schuf Microsoft eine sehr stark an Java
erinnernde Sprache, die alle Möglichkeiten von .NET zu nutzen vermag. Offiziell wird
Java niemals als Ahne angegeben, stattdessen heißt es über die neue Sprache immer, sie
sei eine Sprache, die die Einfachheit von Visual Basic und die Mächtigkeit von C++ in
sich vereint [MS6].
Obwohl man schon zweimal hingucken muss um ein C# von einem Java Programm zu
unterscheiden, gibt es im Innern doch einige Veränderungen. All diese zu beleuchten
würde den Rahmen des Kapitels sprengen, deshalb werden im Folgenden nur einige der
auffälligsten
Neuerungen
gegenüber
den
klassischen
objektorientierten
Programmiersprachen besprochen.
12
3 C#
3.1 Klassen und Vererbung
Ohne einen Mechanismus zur Vererbung ist keine objektorientierte Programmiersprache
vorstellbar, erst recht nicht, wenn es sich um eine Sprache für .NET handelt und alle
Klassen per Definition von System.Object abgeleitet werden. Wie dieses Konzept
umgesetzt wird ist aber wiederum jeder Sprache selbst überlassen, so stellt C# ein ganz
ähnliches Konstrukt wie Java zur Verfügung.
Wie auch dort werden eigene Typen durch Klassen implementiert, sie können
Methoden, Konstruktoren, Konstanten, usw. enthalten. Eine Klasse wird wie folgt
deklariert:
[Modifizierer]
class
Klassenname
[:
{Basisklasse
|
Schnittstelle[, ...]}]
Der Modifizierer wird standardmäßig auf internal gesetzt, dadurch ist die Sichtbarkeit
auf das aktuelle Projekt begrenzt. Ferner stehen dem Programmierer public, protected,
internal protected und private zur Verfügung.
Soll die Klasse von einer anderen Erben, so wird dies durch einen : und dem
Basisklassennamen kenntlich gemacht.
Vererbung
Quelle: C# Kompendium S. 317
Einfachvererbung
Implementierungs Vererbung
class
Mehrfachvererbung
partielle Implemen Tierungsvererbung
abstract class
nicht polymorphe
Implementierung
new
schnittstellenVererbung
interface
polymorphe
Implementierung
virtual,
override
Abbildung 6 Vererbung in C#
Mehrfachvererbung ist in C# nicht vorgesehen, wohl aber die Verwendung von
mehreren interfaces (Schnittstellen). Wie in Java repräsentieren diese das Pflichtenheft
der ableitenden Klassen, sie definieren alles was die erbende Klasse implementieren
muss.
13
3 C#
Sollen übernommene Methoden überschrieben werden können, muss ihnen in der
Basisklasse der Modifizierer virtual und der überschreibenden Methode override
vorangestellt sein. Dadurch, und weil Methoden standardmäßig nicht überschrieben
werden können, wird einem versehentlichen Überschreiben vorgebeugt.
Klassentypen sind Verweistypen und werden dementsprechend auf dem Heap
gespeichert. Hat man aber kleine Datenstrukturen mit Wertsemantik kann es aus
Performancegründen durchaus gewünscht sein sie in den Stack zu laden. Zu diesem
Zweck gibt es in C# den Datentyp struct, er wird wie eine class-Klasse verwendet, kann
aber nicht als Basisklasse verwendet werden.
Um überhaupt auf eine Klasse als Basisklasse zugreifen zu können, muss sie dem
Compiler auch kenntlich gemacht werden. Dafür werden Klassen zu einzelnen
namespaces (Namensräume) zusammengefasst, sie entsprechen in etwa den packages
aus Java. Diese werden dann über das Schlüsselwort using in den eigenen Code
eingebunden. Möchte man nur auf eine bestimmte Klasse zurückgreifen, muss ein Alias
nach dem Muster using GewuenschteKlasse = Namensraum.Klasse;
erzeugt werden.
using System;
namespace Biergarten
{
// Delegat für Ereignis
public delegate void KundeEventHandler();
public class Kunde
{
// Ereignisdefinition
public event KundeEventHandler Bestelle;
int vorrat;
public Kunde (int vorrat) {
this.vorrat = vorrat;
}
// Variable mit get/set Eigenschaften
public int Vorrat {
get {
return vorrat;
}
set {
vorrat = value;
if (vorrat < 1) {
Console.WriteLine("Bier leer, Bestellung ausgelöst");
Bestelle(); // Ereignis auslösen
}
}
}
14
3 C#
public class Bedienung
{
Kunde k;
public Bedienung (Kunde kunde) {
k = kunde;
// Ereigniss abonnieren
kunde.Bestelle += new KundeEventHandler(kunde_Bestelle);
}
}
// Wenn Ereigniss Eintritt ausführen
private void kunde_Bestelle() {
Console.WriteLine("Bed: Da ist es");
k.Vorrat++;
}
public class Rechnung
{
Kunde kunde;
public Rechnung (Kunde k) {
kunde = k;
// Ereigniss abonnieren
kunde.Bestelle += new KundeEventHandler(kunde_Bestelle);
}
}
}
}
private void kunde_Bestelle(){
Console.WriteLine("1 Ereignis kann mehrere Aktionen auslösen");
}
public class Test
{
public static void Main() {
//Kunde sitzt mit 1 Bier im Biergarten
Kunde kunde = new Kunde(1);
//Eine Bedienung nimmt den Kunden wahr
Bedienung bed = new Bedienung(kunde);
//Für den Kunden wird eine Rechnung erstellt
Rechnung k = new Rechnung(kunde);
//Vorrat über set Eigenschaft verringert, Bestellung ausgelöst
kunde.Vorrat--;
Console.ReadLine();
}
}
Quelltext 1
Beispiel mit Delegaten und Eventbehandlung
3.2 Grundsätzlicher Aufbau
Wie in Quelltext 1 zu sehen, sind die Unterschiede zwischen C# und Java im
syntaktischen Aufbau eher gering. Methodennamen werden per CLS-Konvention groß
15
3 C#
geschrieben und die Einstiegsmethode Main() kann verschiedene Signaturen haben. Bei
der Kompilierung fällt auf, dass die Datei nicht zwangsläufig so heißen muss, wie die
Klasse. Auch mehrere vollwertige public Klassen sind innerhalb einer einzelnen Datei
erlaubt.
3.3 Eigenschaften
Die objektorientierte Programmierung erlaubt eine leichte Wiederverwendung von
einmal geschriebenen Code, daher sollten Datenfelder einer Klasse vor falschem Zugriff
geschützt sein. In Java müssen spezielle get- und set-Methoden geschrieben werden, C#
hat dafür das aus Visual Basic und Delphi bekannte Konstrukt der Properties verfeinert
und stellt dem Programmierer Eigenschaften zur Verfügung. Ihre Implementierung ist
gut in der Klasse Kunde zu sehen. Auf die private Integer Variable vorrat wird von
außen über die get und set Eigenschaften des public property Vorrat zugegriffen. Wie
der Zugriff funktioniert erkennt man in der Testklasse. Auch nur lesbare Properties sind
möglich, zu diesem Zweck wird der set Teil einfach weggelassen.
3.4 Ereignisbehandlung und Delegaten
Klassische
Funktionszeiger
haben
keinen
Platz
mehr
in
einer
typsicheren
objektorientierten Programmiersprache. In Java gibt keinen äquivalenten Ersatz dafür,
stattdessen muss der Programmierer inner classes und interfaces verwenden.
C# geht einen eleganteren Weg und führt das Konstrukt der Delegaten ein, die als
typsichere objektorientierte Funktionszeiger, die sogar im Stande sind mehrere
Methoden zu delegieren, verstanden werden können. Delegaten dienen in den meisten
Fällen als Platzhalter für die eigentlichen Callback-Methoden. Die wohl wichtigste
Funktion haben die Delegaten bei der Ereignisbehandlung, speziell hierfür stellt C#
zusätzlich noch den Verweistyp event zur Verfügung.
Delegaten bilden in C# einen eigenen Datentyp (delegate), der sich ähnlich wie Klassen
verhält - so wird in Quelltext 1 der Delegat KundeEventHandler mit Hilfe von new
angelegt. Bei diesem melden sich im Verlauf die Methoden Bedienung und Rechnung
16
3 C#
an und registrieren je eine ihrer Funktionen als Rückruffunktion. In der Auslösenden
Methode des Kunden, wird ein Ereignis mit dem Delegaten verknüpft. Sobald dies
eintritt werden automatisch die beim Delegaten registrierten Methoden ausgeführt.
3.5 Quicksort
Mit Hilfe des Quicksort Algorithmus soll ein Vergleich zwischen Java und C# gezogen
werden. Als Basis dienen die .NET Version 1.1 und die JRE 1.4.1_02. Für das
Programmieren wird Visual Studio .NET verwendet, dieses ist speziell auf die
Programmierung mit C# abgestimmt und erleichtert den Überblick zu behalten. Dieser
Vorteil für C# muss bei einem Vergleich der Implementierungsgeschwindigkeit
berücksichtigt
werden,
mit
einer
explizit
auf
Java
abgestimmten
Entwicklungsumgebung würde auch das Programmieren in dieser Sprache leichter
fallen.
Die eigentliche Quicksortmethode unterscheidet sich in Java und C# lediglich durch die
in der CLS festgelegten Benennungskoventionen.
static void Quicksort (int[] a,
static void quicksort (int[] a,
int L, int R)
int L, int R)
{
{
int m = a[(L + R) / 2];
int m = a[(L + R) / 2];
int i = L;
int i = L;
int j = R;
int j = R;
while (i <= j)
while (i <= j)
{
{
while (a[i] < m) i++;
while (a[i] < m) i++;
while (m < a[j]) j--;
while (m < a[j]) j--;
if (i <= j)
if (i <= j)
{
{
Swap(a, i, j);
swap(a, i, j);
i++;
i++;
j--;
j--;
}
}
}
}
if (L < j) Quicksort(a, L, j);
if (L < j) quicksort(a, L, j);
if (i < R) Quicksort(a, i, R);
if (i < R) quicksort(a, i, R);
}
}
Quelltext 2 Quicksort in C#
Quelltext 3 Quicksort in Java
Das Implementieren geht in beiden Sprachen schnell von Statten, nach wenigen
Minuten sind die Quicksort Methoden fertiggestellt. Auch das Testen mit einer kleinen
main-Methode läuft in beiden Sprachen in etwa gleich zügig ab, hierbei fällt in
17
3 C#
VisualStudio der sehr gefällige Debug-Modus für C# ins Auge, man behält ständig den
Überblick über jede einzelne Variable.
Die gesamte Prozedur hat in C# in etwa zwei Stunden gedauert und noch eine weitere
um den Code nach Java zu portieren, der zweite Schritt wäre aufgrund der geringen
Unterschiede mit einer auf Java abgestimmten Entwicklungsumgebung sehr wahrscheinlich schneller bewältigt worden. Der vollständige Quellcode beider Programme ist
im Anhang enthalten.
Für einen Geschwindigkeitsvergleich zwischen beiden Sprachen erscheint es sinnvoll
mehr als das Sortieren eines einzelnen Arrays zu betrachten, deshalb gilt es Methoden
zum automatischen Erzeugen und Füllen von Arrays zu schreiben. Zur Zeitmessung
wird die Differenz der Zeit vor und nach dem Quicksortalgorithmus genommen. Dabei
fällt auf, dass kleine Arrays oft noch vor einem neuen Zeitsignal sortiert sind. Um dieser
Messungenauigkeit etwas entgegenzuwirken, werden 10.000 Arrays verschiedener
Länge getestet. Zusätzlich durchlaufen je 10.000 sortierte und unsortiere Arrays der
Länge 100.000 die Quicksort-Methode.
Quicksort
Unsortierte Arrays unteschiedlicher
Länge
Unsortierte Arrays der Länge
100.000
C#
Java
Sortierte Arrays der Länge 100.000
0
5
10
15
20
25
30
35
40
45
50
Durchschnittliche Zeit pro Array im ms
Abbildung 7 Geschwindigkeitsvergleich Quicksort auf einem Athlon 900
In Abbildung 4 lässt sich erkennen, dass C# gegenüber Java einen Geschwindigkeitsvorteil von ca. 30 % aufweisen kann. Diesen Eindruck bestätigt ebenfalls die Messung
der gesamten Programmlaufzeit, in die auch das automatische Erzeugen der Arrays
einfließt. Das Ergebnis geht konform mit Messungen der Zeitschrift c't, in
18
3 C#
Geschwindigkeitsvergleichen kamen A. Schäpers und R. Huttary auf ähnliche
Ergebnisse. [c't]
4 Fazit
.NET und C# können für alle erdenklichen Anwendungen herangezogen werden, durch
als unsafe deklarierten Code ist sogar Hardwarenahe Programmierung möglich. Beim
momentanen Stand der Technik werden geschwindigkeitslastige Anwendungen wie 3DSpiele oder rechenintensive Simulationen wohl weiterhin in C++ geschrieben. Mit einer
verbesserten Version der Laufzeitumgebung könnte der Performancenachteil aber weiter
verringert werden.
Ob es sich für eingefleischte Java-Programmierer lohnt auf C# umzusteigen ist noch
nicht klar zu sagen, je nach Anwendungsgebiet hat mal die eine oder die andere Sprache
die Nase vorn. Zudem werden auch in der für Sommer 2004 angekündigten JavaVersion 1.5 einige Nachteile gegenüber .NET ausgemerzt [CW]. Auch professionelle
Entwickler sind sich zur Zeit nicht unbedingt einig, einige favorisieren C# und .NET,
„weil sie neuer ist und sehen konnte, was bei den alten Technologien falsch war“
[DNM]. Andere vertrauen lieber auf das bekannte Java um nicht noch abhängiger von
Microsoft und seiner Lizenzpolitik zu werden. Das Marktforschungsinstitut Garnter
traut beiden Plattformen in den nächsten Jahren eine in etwa gleich große Verbreitung
zu [IW].
Sollte Microsoft seine Ankündigungen wahr machen und in Zukunft die Anwendungsentwicklungen auf die Basis .NET und C# stellen, wird in der Windowswelt wohl kein
Weg daran vorbei führen. In Puncto Plattformunabhängigkeit hat Java zur Zeit zwar
noch eindeutig die Nase vorn, aber auch an diesem Vorsprung fängt .NET dank
Projekten wie Mono langsam zu Knabbern an.
19
5 Literaturverzeichnis
5 Literaturverzeichnis
[MS1]
Microsoft: Chancery Software and Microsoft .NET Technology Empower
Learners And Enhance Solutions for Schools,
http://www.microsoft.com/presspass/press/2001/jun01/0625ChanceryPR.asp.
[MS2]
Microsoft: Definition der .NET Grundkonzepte,
http://www.microsoft.com/germany/themen/net/grundkonzepte.mspx.
[ECMA1] ECMA: Standard ECMA–335-Common Language Infrastructure, ECMA
2002.
[ISO1]
ISO: ISO/IEC 23271- Information technology -- Common Language
Infrastructure, ISO 2003.
[MS3]
Microsoft: Technology Overview,
http://msdn.microsoft.com/netframework/technologyinfo/Overview.
[MSR]
Don Syme: ILX: Extending the .NET Common IL for Functional Language
Interoperability, Babel 2001,
http://research.microsoft.com/projects/ilx/babel01.pdf.
[ECMA2] ECMA: Standard ECMA–334-C# Language Specification, ECMA 2002.
[ISO2]
ISO: ISO/IEC 23270-Information technology -- C# Language Specification,
ISO 2003.
[MONO]
The Mono Project, http://www.go-mono.org.
[DG]
DotGNU Project, http://www.dotgnu.org.
[MS4]
Erik Meijer, Jim Miller: Technical Overview of the Common Language
Runtime, S. 4, http://research.microsoft.com/~emeijer/Papers/CLR.pdf.
[SAL]
Salamander .NET Decompiler,
http://www.remotesoft.com/salamander/index.html.
20
5 Literaturverzeichnis
[C#K02]
A. Schäpers, R. Huttary, Dieter Bremers: C# Kompendium, Markt und
Technik 2002.
[C#21]
Dirk Louis, Shinja Strasser: C# in 21 Tagen, S. 270, Markt und Technik
2002.
[CW]
Wolfgang Sommergut: Java 1.5 soll .NET-Entwickler ködern,
http://www.computerwoche.de/index.cfm?pageid=255&artid=50356&main
_id=50356&category=160&currpage=5&type=detail&kw=.
[.NETFR] Dr. Holger Schwichtenberg: Das .NET Framework,
http://www.dotnetframework.de/default2.aspx?start=http://www.dotnetfram
ework.de/(ai5vtr45kjg1ivz20bb0kv45)/
dotnet/DOTNET_Framework_Einfuehrung.asp.
[MS5]
Microsoft: C#, J# und allgemeine Migrationsthemen,
http://www.microsoft.com/germany/ms/msdnbiblio/show_all.asp?siteid=53
0229.
[MS6]
Michael Willers: Die .NET Common Language Runtime,
http://www.microsoft.com/germany/ms/msdnbiblio/show_all.asp?siteid=47
6316.
[c't]
A. Schäpers, R. Huttary: C#, Java, C++ und Delphi im Effizienztest, c't
19/2003, S. 204-207 und c't 21/200, S. 222-227, Heise Verlag.
[DNM]
Stefan Wunderlich: Stefan Zill und Andraz Vrenko von Avanade im
Gespräch, http://dotnetmag.de/itr/online_artikel/show.php3?nodeid=31&id=171.
[IM]
Michael Bauer, Werner Fritsch: Java oder .NET?,
http://www.informationweek.de/index.php3?/channels/channel21/022620.ht
m.
[C#N02]
Peter Drayton, Ben Albahari, Ted Neward: C# in a Nutshell, O'ReillyVerlag 2002.
21
6 Anhang
6 Anhang
6.1 Quicksort in C#
using System;
class AufgabeQuickSort
{
static long zeit = 0;
static long zeit100000 = 0;
static long zeitSort = 0;
static long zeitUnsort = 0;
static void Quicksort (int[] a, int L, int R)
{
int m = a[(L + R) / 2];
int i = L;
int j = R;
while (i <= j)
{
while (a[i] < m) i++;
while (m < a[j]) j--;
if (i <= j) {
Swap(a, i, j);
i++;
j--;
}
}
if (L < j) Quicksort(a, L, j);
if (i < R) Quicksort(a, i, R);
}
static void Swap (int[] a, int L, int R)
{
int temp = a[L];
a[L] = a[R];
a[R] = temp;
}
static void ArrayAusgeben(int[] a)
{
foreach (int elem in a)
{
Console.Write("{0} ",elem);
}
Console.WriteLine("\n");
}
static void ErzeugeArraySort()
{
int[] a = new int[100000];
for (int i = 0; i < 100000; i++)
{
a[i] = i;
22
6 Anhang
}
}
long start = DateTime.Now.Ticks; //Ein Tick dauert 100ns
Quicksort(a,0,a.Length-1);
long dauer = DateTime.Now.Ticks - start;
zeitSort += dauer;
static void ErzeugeArray100000()
{
Random zufallszahlen = new Random();
int[] a = new int[100000];
for (int i = 0; i < 100000; i++)
{
a[i] = zufallszahlen.Next(1,1000000) - 500000;
}
long start = DateTime.Now.Ticks;
Quicksort(a,0,a.Length-1);
long dauer = DateTime.Now.Ticks - start;
zeit100000 += dauer;
}
static void ErzeugeArrayZZ()
{
Random zufallszahlen = new Random();
int zz = zufallszahlen.Next(1,100001);
int[] a = new int[zz];
for (int i = 0; i < zz; i++)
{
a[i] = zufallszahlen.Next(1,1000000) - 500000;
}
long start = DateTime.Now.Ticks;
Quicksort(a,0,a.Length-1);
long dauer = DateTime.Now.Ticks - start;
zeit += dauer;
}
static void Main(string[] args)
{
int[] a = {-213,52,234,-7,13,4,661,-123,43,73,12,-1};
ArrayAusgeben(a);
Quicksort(a,0,a.Length-1);
ArrayAusgeben(a);
int anzArrays = 10000;
for (int i = 0; i<anzArrays;i++)
{
ErzeugeArray100000();
ErzeugeArrayZZ();
ErzeugeArraySort();
}
Console.WriteLine("Quicksort wurde für {0} arrays unterschiedlicher
Länge aufgerufen.\nDurchschnittlich dauerte das Sortieren {1}
ms\n",anzArrays,zeit/anzArrays/10000);
Console.WriteLine("Quicksort wurde für {0} arrays der Länge 100.000
aufgerufen.\nDurchschnittlich dauerte das Sortieren {1}
ms\n",anzArrays,zeit100000/anzArrays/10000);
Console.WriteLine("Quicksort wurde für {0} sortierte Arrays der
Länge 100.000 aufgerufen.\nDurchschnittliche brauchte Quicksort {1}
ms\n",anzArrays,zeitSort/anzArrays/10000);
Console.ReadLine();
}
}
23
6 Anhang
6.2 Quicksort in Java
import java.util.*;
class qs
{
static long zeit = 0;
static long zeit100000 = 0;
static long zeitSort = 0;
static void quicksort (int[] a, int L, int R)
{
int m = a[(L + R) / 2];
int i = L;
int j = R;
while (i <= j)
{
while (a[i] < m) i++;
while (m < a[j]) j--;
if (i <= j)
{
swap(a, i, j);
i++;
j--;
}
}
if (L < j) quicksort(a, L, j);
if (i < R) quicksort(a, i, R);
}
static void swap (int[] a, int L, int R)
{
int temp = a[L];
a[L] = a[R];
a[R] = temp;
}
static void arrayAusgeben(int[] a)
{
for (int i = 0; i < a.length; i++)
{
System.out.print(a[i]+" ");
}
System.out.println("\n");
}
static void erzeugeArraySort()
{
int[] a = new int[100000];
for (int i = 0; i < 100000; i++)
{
a[i] = i;
}
Date start = new Date();
quicksort(a,0,a.length-1);
Date fertig = new Date();
zeitSort += fertig.getTime() - start.getTime();
}
static void erzeugeArray100000()
24
6 Anhang
{
}
Random zufallszahlen = new Random();
int[] a = new int[100000];
for (int i = 0; i < 100000; i++)
{
a[i] = zufallszahlen.nextInt(1000000) - 500000;
}
Date start = new Date();
quicksort(a,0,a.length-1);
Date fertig = new Date();
zeit100000 += fertig.getTime() - start.getTime();
static void erzeugeArrayZZ()
{
Random zufallszahlen = new Random();
int zz = zufallszahlen.nextInt(100001);
int[] a = new int[zz];
for (int i = 0; i < zz; i++)
{
a[i] = zufallszahlen.nextInt(1000000) - 500000;
}
Date start = new Date();
quicksort(a,0,a.length-1);
Date fertig = new Date();
zeit += fertig.getTime() - start.getTime();
}
public static void main(String[] args)
{
int[] a = {-213,52,234,-7,13,4,661,-123,43,73,12,-1};
arrayAusgeben(a);
quicksort(a,0,a.length-1);
arrayAusgeben(a);
int anzArrays = 10000;
for (int i = 0; i<anzArrays;i++)
{
erzeugeArray100000();
erzeugeArrayZZ();
erzeugeArraySort();
}
System.out.println("Quicksort wurde für "+anzArrays+" Arrays
unterschiedlicher Länge aufgerufen.\nDurchschnittlich dauerte das
Sortieren "+zeit/anzArrays+" ms\n");
System.out.println("Quicksort wurde für "+anzArrays+" Arrays der
Länge 100.000 aufgerufen.\nDurchschnittlich dauerte das Sortieren
"+zeit100000/anzArrays+" ms\n");
System.out.println("Quicksort wurde für "+anzArrays+" sortierte
Arrays der Länge 100.000 aufgerufen.\nDurchschnittlich dauerte das
Sortieren "+zeitSort/anzArrays+" ms\n");
}
}
25
Herunterladen