PhiLIOsoph

Willkommen auf meiner Homepage. Mein Name ist Robert Nitsch und ich studiere momentan B.Sc. Informatik an der TU Darmstadt.

In diesem Blog schreibe ich seit Ende 2006 über meine Ansichten, Projekte und mehr oder weniger alltäglichen Erlebnisse. Ab und zu schreibe ich auch eine Anleitung bzw. ein Tutorial, um ein bestimmtes Problem zu lösen oder Hilfestellung zu geben. Solltest du Gefallen an meinen Texten finden kannst du selbstverständlich auch meinen Feed abonnieren.



Seite:  Vorherige Seite 1 2 ...4 5 6 ...25 26 Nächste Seite
31.03.2009

Java Generics vs. Java Listen

Filed under: Informatik,Java,Studium,Tutorials — Robert @ 22:09:35

Beim Thema Generics in Verbindung mit Listen geht vieles drunter und drüber. Dabei ist die Sache gar nicht so schwer, wenn man das Prinzip einmal verstanden hat…

Zunächst einmal: Generics ermöglichen mittels formaler Typparamter, dass Klassen (und Funktionen), die bestimmte Dienste zur Verfügung stellen, mit mehreren Datentypen umgehen können.
Wenn wir zum Beispiel zwei beliebige Objekte als “Paar” verwalten wollen, dann benötigen wir eine entsprechende Klasse mit zwei Attributen, einer Möglichkeit die Objekte darin zu speichern und wieder auszulesen.

An sich nichts schweres:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Pair {
    Object obj1, obj2;
    // Das Einspeichern von Objekten ist der Einfachheit halber nur beim Erzeugen des Paares möglich...
    Pair(Object obj1, Object obj2) {
        this.obj1 = obj1;
        this.obj2 = obj2;
    }
    public Object getFirst() {
        return this.obj1;
    }
    public Object getSecond() {
        return this.obj2;
    }
}

Diese Klasse hat aber einen Haken. Beim Einspeichern gehen die Informationen über den Typ der eingespeicherten Objekte verloren. Wenn wir den Typ wiederherstellen wollen müssen wir einen expliziten Cast durchführen. Andernfalls erhalten wir immer nur Objects.

Pair paar = new Pair(new MeinApfel(), new MeinApfel());
MeinApfel apfel = (MeinApfel)paar.getFirst();

Bei Listen ist das Problem noch dramatischer. Ohne Generics muss man bei jeder Leseoperation auf einer Liste explizit casten:

Vector liste = new Vector();
for(int i=0; i<10; i++)
    liste.add(new MeinApfel());
// ...
for(int i=0; i<liste.size(); i++)
    esseApfel((MeinApfel) liste.get(i));

Bei so vielen expliziten Casts riskiert man außerdem ClassCastExceptions, falls das referenzierte Objekt nicht zu dem entsprechenden Typ konvertiert werden kann.

Abhilfe schaffen hier die Generics. Das soll erstmal am Beispiel der obigen Pair-Klasse demonstriert werden, die folgendermaßen generisch gemacht werden kann:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Pair<A,B> {
    A obj1;
    B obj2;
    Pair(A obj1, B obj2) {
        this.obj1 = obj1;
        this.obj2 = obj2;
    }
    public A getFirst() {
        return this.obj1;
    }
    public B getSecond() {
        return this.obj2;
    }
}

A und B sind sogenannte formale Typparameter, die in diesem Fall für beliebige Typen stehen.
Folgendermaßen erzeugen wir jetzt Paare von Integer-Objekten:

// anschaulich wird hier A = Integer und B = Integer gesetzt
Pair<Integer, Integer> paar = new Pair<Integer, Integer>(new Integer(2), new Integer(3));
 
// kein Cast mehr nötig, weil auch die Signatur von getFirst() quasi dynamisch an Integer angepasst wurde
Integer zahl = paar.getFirst();

Dasselbe ist natürlich auch bei Listen möglich, die bei der Einführung der Generics auch gleich generisch gemacht wurden. Bei Listen gibt es im Gegensatz zu dem Pair-Beispiel nur einen formalen Typparameter, der den Typ der gespeicherten Elemente festlegt.

// Eine Liste von Elementen des Typs "MeinApfel" anlegen...
Vector<MeinApfel> liste = new Vector<MeinApfel>();
liste.add(new MeinApfel());
 
// ...
 
// funktioniert problemlos, da die Signatur von get() genau wie getFirst() aus dem ersten Beispiel an den ggb. Typ angepasst wurde
MeinApfel apfel = liste.get(0);

Richtig trickreich wird es, wenn Funktionen, die Listen entgegennehmen, generisch gemacht werden sollen. Angenommen wir wollen eine Funktion schreiben, die eine Liste von Nahrungsmitteln entgegennimmt und ihr Gewicht bestimmt.
In diesem Fall werden sogenannte Wildcards benötigt.

Intuitiv müsste die Funktion folgendermaßen aussehen:

public double wiege(List<Nahrungsmittel> liste) {
    // ...
}

Diese Funktion würde aber entgegen unserer Intuition bspw. keine Liste mit Äpfeln annehmen, obwohl Äpfel in der Klassenhierarchie ganz klar ein Subtyp von Nahrungsmittel darstellen würden (public class Apfel extends Nahrungsmittel).
Es funktioniert deshalb nicht, weil List<Apfel> einfach nicht kompatibel ist zu List<Nahrungsmittel>. Beispiel:

1
2
3
Vector<Nahrungsmittel> liste1 = new Vector<Nahrungsmittel>(); // OK!
Vector<Apfel> liste2 = new Vector<Apfel>(); // OK!
liste1 = liste2; // FEHLER: cannot convert from Vector<Apfel> to Vector<Nahrungsmittel>

Dieser Code wird vom Compiler deshalb nicht akzeptiert, weil man in eine Liste von Äpfeln keine Nahrungsmittel einfügen kann. Wenn liste1 vom Typ List<Nahrungsmittel> auf liste2 vom Typ List<Apfel> verweisen würde, dann würde das bspw. die Signatur von liste1.add(…) verletzen, denn liste1.add(new Nahrungsmittel()) wäre nicht möglich, weil liste1 auf eine Liste von Äpfeln (und nur Äpfel!) zeigen würde. Das meine ich, wenn ich schreibe, dass List<Apfel> nicht kompatibel ist zu List<Nahrungsmittel>.

Das Problem löst man mit besagten Wildcards:

public double wiege(List<? extends Nahrungsmittel> liste) {
    // akzeptiert alle Listen, deren Elemente Nahrungsmittel oder Subtypen davon sind
}

? steht für einen unbekannten Typ. Bekannt ist bei einer List<?> nur, dass – wie bei jeder typ-parametrisierten Liste – die Elemente, die in der Liste gespeichert sind, alle vom selben (unbekannten) Typ sind.
Das “extends Nahrungsmittel” schränkt die möglichen Typen hier aber insofern ein, als dass Nahrungsmittel die “obere Schranke” darstellt. ? darf hier also vom Typ Nahrungsmittel oder ein Subtyp davon sein.

Es gibt auch die Möglichkeit eine untere Schranke zu definieren: List<? super Nahrungsmittel> bzw. allgemein List<? super X>. Erlaubt sind dann Elemente vom Typ X oder Supertypen davon.

Bleiben wir zunächst bei unserer List<? extends Nahrungsmittel>. Wir können zumindest eingeschränkt mit einer solchen Liste arbeiten: Lesen, aber nicht Einfügen. Das Einfügen klappt deshalb nicht, weil der genaue Typ der Liste nicht bekannt ist. Zwar kann man einen Apfel zu einem Nahrungsmittel konvertieren. Aber die Liste enthält ja nicht notwendigerweise Nahrungsmittel. Sie kann genausogut Birnen enthalten – daher darf man in eine solche Liste keine neuen Objekte einfügen.

Im Folgenden eine Tabelle, die die erlaubten Operationen auf einer Liste dokumentiert:

Typ Lesen Typ der gelesenen Objekte Einfügen Einfügbare Typen
List Ja Object Ja Beliebig
List<?> Ja Object Nein -
List<X> Ja X Ja X oder Subtypen von X
List<? extends X> Ja X Nein -
List<? super X> Ja Object Ja X oder Subtypen von X

Bleibt nur noch die Frage zu klären, warum man in eine List<? super X> Elemente vom Typ X und Subtypen von X einfügen darf. Bei List<? extends X> ist das schließlich auch nicht möglich. Nunja, bei extends X sind die Elemente der Liste vom Typ X oder Subtypen davon, d.h. spezieller. Bei super X sind die Elemente vom Typ X oder Supertypen von X, d.h. allgemeiner. Daher kann man Objekte vom Typ X oder von einem Subtyp von X nach Belieben in eine solche Liste einfügen, weil man Objekte von einem bestimmten Typ immer zu einem allgemeineren Typ konvertieren kann.
Faustregel: Jeder Apfel ist ein Obst, aber nicht jedes Obst ein Apfel!

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Technorati
  • Google Bookmarks
  • Yigg
  • Digg
21.02.2009

Mathematiker stehlen Lebenszeit

Filed under: Informatik,Mathematik,Real Life,Studium — Robert @ 22:39:55

[Hinweis: Dieser Artikel gibt meine persönliche Meinung wieder.]

So… es muss jetzt mal raus. Seit Montag haben wir Semesterferien, d.h. es gibt keine Vorlesungen/Übungen mehr und wir bereiten uns jetzt auf die Prüfungen vor. Die erste Prüfung ist Mathematik für Informatiker I.

Ich habe daher seit Montag jeden Tag etwas geübt und auch damit angefangen, das Mathe-Skript vom Professor mal ernsthaft und konzentriert durchzugehen. Das heißt, dass ich v.a. versuche, die vielen Beweise zu verstehen, um die ich bisher häufig einfach einen Bogen gemacht habe. Diese Beweise sind allerdings bis auf ganz wenige Ausnahmen absolut unverständlich… es werden z.B. ständig die unmöglichsten Umformungen gemacht ohne, dass das auch nur in einer Randnotiz vermerkt wäre – zum Kotzen!

Nach einem vollen Semester Mathematik – in dem ich mir wirklich Mühe gegeben habe, zu verstehen, was der Professor da immer predigt – und nach mehrfachen Versuchen, den Mathematikern doch noch eine Chance zu geben, lautet mein Fazit ein für allemal:

  • Mathematiker erklären ihr Fach absichtlich schlecht, obwohl sie selbst bspw. von Beweisen fordern, dass sie bloß gut kommentiert und nachvollziehbar sein sollen
  • Mathematiker stehlen dadurch Lebenszeit, die man auch besser nutzen könnte (um mal auf den Titel zurückzukommen)

Ich bin ja sowas von angepisst von dieser abartigen Arroganz, die die Mathematiker bei uns an der Uni an den Tag legen… das ist ja sowas von erbärmlich. Es gibt nichts, was der dümmste Dorftrottel nicht besser erklären könnte als ein Mathematiker – ich kann mir jedenfalls nichts vorstellen.
So oft haben meine Kommilitonen und ich schon gestöhnt “oh man, das ist doch eigentlich total einfach”, nachdem wir endlich etwas verstanden hatten, was uns die lieben Mathematiker auf die gottverdammt dämlichste Art und Weise versuchten, beizubringen (dieses Gefühl wird wohl jeder kennen).

Warum tun sich Mathematiker so schwer damit, ihr Fach menschlich zu erklären? Der Formalismus beißt sich nämlich kein bisschen mit Verständlichkeit (das Gegenteil wird immer von Mathematikern behauptet)!
Ich schätze, dass die Mathematiker einfach nicht wollen, dass man ihr Fach so darstellt, wie es nunmal ist: relativ simpel, wenn man’s vernünftig erklärt. Oder es ist einfach eine sehr alte Tradition und jeder Professor sagt sich “warum sollen es die Studenten von heute besser haben als ich – die sollen auch schuften müssen, auf die vernünftigen Erklärungen scheiße ich”

Zum Schluss möchte ich noch eines sagen: Mathe ist nur eine von 4 Lehrveranstaltungen in diesem Semester. Jede Lehrveranstaltung hat es gewaltig in sich – und man ist gelegentlich immer mal frustriert. Das ist normal, wenn man studiert – erst Recht bei Informatik (es ist einfach schwer). Aber nirgends ist es a) so heftig wie bei Mathematik und b) nirgends habe ich auch nur den geringsten Anlass dazu zu denken, dass die Professoren/Tutoren ihr Fach mit Absicht schwer erklären. Im Gegenteil: Überall versucht man den Stoff so verständlich und anschaulich rüberzubringen wie nur irgendwie möglich! Nur bei Mathe nicht. Da ist es gerade andersrum… und DAS ist es, was mich so sauer macht.
Außerdem ist es so, dass Mathematik nicht nur bei uns so verhasst ist. Von verschiedenen Leuten aus meinem Abi-Jahrgang und von Studenten aus anderen Fachbereichen höre ich (im Wesentlichen) genau dasselbe.

Letztenendes muss ich da so oder so durch – und ich werde es schaffen! Und von Zeit zu Zeit werde ich den Mathematikern gehörig in den Arsch treten, indem ich ihnen zeige, wie man es besser macht…

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Technorati
  • Google Bookmarks
  • Yigg
  • Digg
07.02.2009

Trafficshaping mit cFosSpeed – Die ultimative Internet-Optimierung

Filed under: Erfahrungsberichte,Informatik,Internet,PC,Tools — Robert @ 14:51:31

Neulich habe ich durch Zufall von cFosSpeed gehört, einer Software, die sogenanntes Trafficshaping betreibt. Das Trafficshaping von cFosSpeed ermöglicht die Priorisierung von Protokollen und/oder Anwendungen bei dem Zugriff auf das Internet.

Das führt dazu, dass man auch während größerer Downloads mit gefühlter voller Bandbreite surfen kann (habe ich selbst getestet und kann ich zu 100% bestätigen). Man merkt dann kaum noch, dass die Leitung in Wirklichkeit voll ausgereizt ist (= optimal).

Ich habe es gestern auch mal auf die Spitze getrieben: Ich habe eine sehr große Datenmenge heruntergeladen und währenddessen über das Internet ein Strategiespiel gespielt (bei diesem Spiel kommt es v.a. auf gute Reaktionszeiten an, d.h. auf eine gute Internet-Verbindung). Normalerweise wäre das nicht möglich gewesen, da das Spiel dauernd geruckelt hätte usw. Da ich aber cFosSpeed klargemacht habe, dass der Download nicht so wichtig ist wie das Spiel, habe ich den Download im Hintergrund nicht beim Zocken gespürt. Dabei war die Leitung die ganze Zeit zu 100% ausgereizt. Die Bandbreite wurde von cFosSpeed einfach geschickt zwischen den Anwendungen aufgeteilt – entsprechend meiner Einstellungen.

Ganz ehrlich… für DSL 1000 – Kuhkaff – Menschen wie mich ist cFosSpeed eine erstklassige, wenn auch leider nicht kostenlose Software. Ich überlege mir ernsthaft, mir diese Software nach Ablauf der 30 Tage – Demo zuzulegen (zudem man lebenslang zu allen Updates/Upgrades Zugang hat).
Die Bedienung von cFosSpeed ist zwar etwas gewöhnungsbedürftig, aber immerhin sind die populären Anwendungen/Prokotolle bereits vorkonfiguriert. So wird bspw. das Surfen und das Zocken von Anfang an mit einer hohen Priorität bedacht. Filesharing-Prokotolle werden auch schon von Haus aus “gedrosselt”. Sollte man doch mal eine Anwendung hinzufügen wollen, die nicht bereits in cFosSpeed eingetragen ist, dann ist das problemlos möglich.

Alles in allem kann ich cFosSpeed nur uneingeschränkt weiterempfehlen und hoffe, dass auch ihr von meiner “Entdeckung” profitiert. Probiert es einfach aus, es ist wirklich herrlich!

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Technorati
  • Google Bookmarks
  • Yigg
  • Digg
Seite:  Vorherige Seite 1 2 ...4 5 6 ...25 26 Nächste Seite
« Vorherige SeiteNächste Seite »

© Robert Nitsch
(Powered by WordPress)