FB18 - Das Forum für Informatik

fb18.de / Off-Topic / Allgemeines

Your daily dose of WTF featuring: Programming

Your daily dose of WTF featuring: Programming 2005-12-04 19:41
Wolf
Von einem Arbeitskollegen:

/* Ausgabe.java */ public class Ausgabe { public static void main(String[] args) { KlasseMitPrivateA a1 = new KlasseMitPrivateA(1); KlasseMitPrivateA a2 = new KlasseMitPrivateA(2); a2.setzeAnderesA(a1, 3); System.out.println("a1 - " + a1.toString()); System.out.println("a2 - " + a2.toString()); } } class KlasseMitPrivateA { private int a; public KlasseMitPrivateA(int a) { this.a = a; } public void setzeAnderesA(KlasseMitPrivateA andereKlasse, int neuerWert) { andereKlasse.a = neuerWert; } public String toString() { return "" + a; } } An der Ausgabe des Programms kann man erkennen, dass über das Objekt a2 auf private Membervariablen des Objekts a1 zugegriffen wurde:

a1 - 3
a2 - 2

Also kann man beliebige private-Werte anderer Instanzen überschreiben, wenn man dazu eine Instanz der selben Klasse benutzt. Wozu ist dann private gut? Oder in anderen Worten: WTF!

Edit: Tschuldigung, kleiner Fehler beim Abtippen.

Re: Your daily dose of WTF featuring: Programming 2005-12-04 20:07
Anonymer User
Ich mag sonst Java überhaupt nicht, aber das was du beschreibst ist ein recht universelles Prinzip, ist z.B. auf C++ auch übertragbar. Ich kann dir jetzt aber auch nicht prägnant erklären warum ich dieses Prinzip auch sinnvoll finde :-(
Vielleicht als Ansatz:
Das Autor der Klasse sollte wissen was er macht, für ihn wäre es zu einschränkend, wenn er nur auf "private" Member desselben Objektes zugreifen könnte. Oder von einer anderen Richtung her: Das was du beschreibst schmälert den Wert von "private" nicht wirklich, weil es eben nicht den Zugriff von "Unberechtigten" ermöglicht. Es bleibt nämlich dabei das der Autor der Klasse selber regelt wer Zugriff bekommt und wer nicht.

Re: Your daily dose of WTF featuring: Programming 2005-12-04 20:09
Wolf
Es bleibt nämlich dabei das der Autor der Klasse selber regelt wer Zugriff bekommt und wer nicht.
Stimmt imho nicht, ich kann z.B. erben (das ist jetzt aber eine Annahme, müsste ich erstmal testen).

Re: Your daily dose of WTF featuring: Programming 2005-12-04 20:12
TeyThoon
das hat so schon seine richtigkeit. private/public bezieht sich auf gleiche/verschiedene klasse, nicht gleiche/verschiedene instanz.

Re: Your daily dose of WTF featuring: Programming 2005-12-04 20:16
Wolf
das hat so schon seine richtigkeit. private/public bezieht sich auf gleiche/verschiedene klasse, nicht gleiche/verschiedene instanz.
Das ist schon klar, aber was soll ich mit dem Schlüsselwort, wenn ich es ohne Weiteres generisch umgehen kann? Das ist dann doch keine wirkliche Kapselung mehr!

ich kann z.B. erben
Okay, das scheint nicht zu gehen. Aber über den ClassLoader kommt man da sicher ran, aus ähnlichen Gründen. Der wird intern nämlich eine Instanz erzeugen, um dann privates auszulesen. Ist jetzt vielleicht etwas müßig, das zu konstruieren, aber irritierend finde ich das schon! Ich hätte nicht erwartet, dass irgend jemand das als gute Eigenschaft bezeichnen würde.

Re: Your daily dose of WTF featuring: Programming 2005-12-04 21:13
Anonymer User
Das ist schon klar, aber was soll ich mit dem Schlüsselwort, wenn ich es ohne Weiteres generisch umgehen kann? Das ist dann doch keine wirkliche Kapselung mehr!
Das ist nicht wirklich ein Gegenargument. Denn irgendeine Möglichkeit auf die Daten zuzugreifen gibt es doch immer. Mal ein Blick auf C++: Dort könnte z.B. irgend ein Blödmann auf die Idee kommen, mit dem Präprozessor "private" in "public" umzudefinieren (*), bevor deine Klasse geladen wird. Schon wäre dein ganzer "Schutz" auch wieder zunichte gemacht.

Aber über den ClassLoader kommt man da sicher ran, aus ähnlichen Gründen. Der wird intern nämlich eine Instanz erzeugen, um dann privates auszulesen. Ist jetzt vielleicht etwas müßig, das zu konstruieren, aber irritierend finde ich das schon!
Mal eine Gegenfrage: Wenn du nicht auf "private"-Member zugreifen könntest, wie würdest du dann eine Kopieroperation für die Klasse schreiben? Und wenn du das noch demonstrieren kannst, wie würdest du dann eine *effektive* Kopieroperation schreiben?

Ich möchte dir hier mal einen Link auf einen (relevanten) Teil der C++-Faq von Marshall Cline liefern. Die ist im Allgemeinen gut.
Dieser Teil gilt meiner Meinung nach auch ein gutes Stück für Java. (Und, den Kommentar kann ich mir nicht verkneifen: Da wo Java einer anderen Philosophie folgt, da haben die Erschaffer von Java sich fehlleiten lassen).
http://www.parashift.com/c++-faq-lite/classes-and-objects.html

-

(*): Das ist zwar nicht erlaubt, aber es muss auch nicht zwingend das Compilieren verhindern. Insofern könnte dieser Fall also eintreten.

Re: Your daily dose of WTF featuring: Programming 2005-12-05 00:14
MoKrates
Ich denke, C++ ist kein Vergleich. C++ hat auf Runtime-Ebene keine Abfragen mehr, ob und wie auf einen gewissen Speicherbereich zugegriffen wird, und kann so "private"s nicht mehr schuetzen. Hier wird das "private" einfach nur dadurch realisiert, dass der Identifier von nicht zugriffsberechtigten Bereichen nicht aufgeloest werden kann.

Zitat: http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.8

6.6.8 Example: private Fields, Methods, and Constructors
A private class member or constructor is accessible only within the body of the top level class (§7.6) that encloses the declaration of the member or constructor. It is not inherited by subclasses. In the example:

class Point {
Point() { setMasterID(); }
int x, y;
private int ID;
private static int masterID = 0;
private void setMasterID() { ID = masterID++; }
}

the private members ID, masterID, and setMasterID may be used only within the body of class Point. The6.6.8 Example: private Fields, Methods, and Constructors
A private class member or constructor is accessible only within the body of the top level class (§7.6) that encloses the declaration of the member or constructor. It is not inherited by subclasses. In the example:

class Point {
Point() { setMasterID(); }
int x, y;
private int ID;
private static int masterID = 0;
private void setMasterID() { ID = masterID++; }
}

the private members ID, masterID, and setMasterID may be used only within the body of class Point. They may not be accessed by qualified names, field access expressions, or method invocation expressions outside the body of the declaration of Point.y may not be accessed by qualified names, field access expressions, or method invocation expressions outside the body of the declaration of Point.

Obiges findet man ueber ein paar Klicks als den ersten Hit auf "Java language specs" ueber Google.

Das passt insofern auf Wolfs Beispiel, als dass es in dem entsprechenden Zugriffsberechtigen Block steht.

Es passt nicht, weil der Name in Wolfs Beispiel "qualified" ist. (Der Name enthaelt einen Punkt).

Mo

Re: Your daily dose of WTF featuring: Programming 2005-12-05 01:04
Wolf
Das ist nicht wirklich ein Gegenargument. Denn irgendeine Möglichkeit auf die Daten zuzugreifen gibt es doch immer.
Ist auch klar, aber doch nicht aus der Sprache selber heraus. Natürlich kann ich Quelltext auch anders kompilieren, Bytecode anders interpretieren, Zustände mit einem Freezer auslesen oder was einem so einfällt - die Sprache sollte das in sich nicht anbieten. Das ist mein Verständnis vom Schlüsselwort private.
Vielleicht lag ich da daneben, aber ein "WTF" ist mir über die Lippen gegangen, und ich denke, es ist klar, dass das nicht unbegründet war.
Mal eine Gegenfrage: Wenn du nicht auf "private"-Member zugreifen könntest, wie würdest du dann eine Kopieroperation für die Klasse schreiben? Und wenn du das noch demonstrieren kannst, wie würdest du dann eine *effektive* Kopieroperation schreiben?
Das stinkt doch wieder nach so einem typischen Java-Kompromiss. Erinnert mich an BigDecimal in Java 1.4 - das ist eine C-Bibliothek. Suuper.

Edit: Oder benutzt etwas aus einer C-Bibliothek, bin mir da jetzt nicht so sicher und zu faul, es noch einmal nachzulesen.

Wenn Smalltalk konsequent am Konzept entlang gebaut wurde, warum war das nicht bei Java drin?

Nicht falsch verstehen, ich programmiere gerne in Java. Aber manche Sachen _sind_ einfach komisch.

Der Garbage Collector ist auch so eine Sache - warum darf ich den nicht ignorieren und von Hand discarden? Es gibt doch keinen Grund, das zu verbieten. Er könnte ja immer noch normal weiterarbeiten, wenn ich Instanzen schon geknickt hätte. Das hat für mich nicht viel mit dem Grundkonzept von Java zu tun.

Ich glaube, ich muss mir Java mal noch genauer ansehen.

Re: Your daily dose of WTF featuring: Programming 2005-12-05 01:16
MoKrates
Mach fuer die GC lieber nen neuen Thread auf. Deine Argumente grade laden zum argumentieren grade zu ein:

Ich muss ehrlich sagen: wuerde ich eine GC implementieren, wuerde ich Dir nicht so einfach erlauben, Objekte zu discarden. Unter anderem darum, weil es kaum einen Sinn macht ;) Aber auch deswegen, weil ich meine GC so baue, dass sie sich nicht irrt, wenn sie Objekte loescht. Du wirst Dich irren. Versprochen.

Mo

Re: Your daily dose of WTF featuring: Programming 2005-12-05 11:00
Anonymer User
Ich denke, C++ ist kein Vergleich. C++ hat auf Runtime-Ebene keine Abfragen mehr, ob und wie auf einen gewissen Speicherbereich zugegriffen wird, und kann so "private"s nicht mehr schuetzen.
Darauf wollte ich so ein bisschen hinaus als ich geschrieben habe "Das wo Java von dieser Philosophie abweicht irrten sich die Java-Erschaffer" (sinngemäß). Einen Speicherbereich zu schützen kann eine Programmiersprache nicht garantieren. Sie kann nur die Illusion anbieten. Da ist es besser die Konzepte gar nicht erst zu vermischen: Die Programiersprache soll dem Programmierer *helfen* ein korrektes Programm zu schreiben. Aber um sich vor Angreifern zu schützen, da muss schon das Betriebssystem mitspielen.

Hier wird das "private" einfach nur dadurch realisiert, dass der Identifier von nicht zugriffsberechtigten Bereichen nicht aufgeloest werden kann.
Das ist so nicht korrekt. Namensauflösung geschieht in C++ vor der Kontrolle der Zugriffsrechte. Deutlicher ausgedrückt: Wenn in C++ auf public/protected/private geprüft wird, sind schon alle in Frage kommenden Entitäten gefunden.

An Wolf:
Vielleicht lag ich da daneben, aber ein "WTF" ist mir über die Lippen gegangen, und ich denke, es ist klar, dass das nicht unbegründet war.
Wie ich schon geschrieben habe: Wenn private so funktionieren würde wie du zuerst vermutet hast, dann wäre es zu restriktiv um wirklich brauchbar zu sein. Man könnte vielleicht zwei Schlüsselworte in eine Programmiersprache einführen: Ein "private" so wie du zuerst dachtest, und eins so wie es tatsächlich funktioniert. Aber nur private so wie du dachtest, dass würde vermutlich zu weniger "Schutz", statt zu mehr führen. Dann müsste man nämlich viele Member "public" machen. Und dann hilft die Programmiersprache gar nicht mehr, den Zugriff zu regeln.

Re: Your daily dose of WTF featuring: Programming 2005-12-05 17:11
Brokkoli
Der Garbage Collector ist auch so eine Sache - warum darf ich den nicht ignorieren und von Hand discarden? Es gibt doch keinen Grund, das zu verbieten. Er könnte ja immer noch normal weiterarbeiten, wenn ich Instanzen schon geknickt hätte. Das hat für mich nicht viel mit dem Grundkonzept von Java zu tun.

wenn du ein objekt per hand löschst, was noch irgendwo anders referenziert wird, hättest du referenzen, die in einen ungültigen bereich verweisen, aber trotzdem keine nullpointer sind. man könnte natürlich ähnlich wie beim gc prüfen, ob noch referenzen existieren, wenn jemand ein objekt von hand löschen will - aber das wäre vermutlich von einer ähnlichen komplexität wie ein gc-lauf - daher also alles andere als sinnvoll.

Re: Your daily dose of WTF featuring: Programming 2005-12-05 17:27
MoKrates
Hehe, vor allem, wenn man ein Objekt discarden will, braucht man ja offensichtlich noch mindestens eine Referenz, sonst koennte man dem System ja nicht sagen, _was_ man discarden will ;)

Mo

Re: Your daily dose of WTF featuring: Programming 2005-12-05 19:29
Wolf
Ein "private" so wie du zuerst dachtest, und eins so wie es tatsächlich funktioniert
Das klingt schon viel besser. Warum wurde das nicht realisiert?
Ich konstruiere mal ein Beispiel:
Die Klasse heißt Mensch.
Menschen haben die private Methode rülpsen.
Durch das private, wie wir es vorfinden, kann jeder Mensch jeden anderen rülpsen lassen, da ein Mensch sich selbst ja zum Rülpsen bringen kann.
Das ist doch schlecht!
wenn du ein objekt per hand löschst, was noch irgendwo anders referenziert wird, hättest du referenzen, die in einen ungültigen bereich verweisen, aber trotzdem keine nullpointer sind.
Damit kann man doch umgehen. Die Referenz ist ja als ungültig erkennbar. Also erhält sie keinen Zugriff auf den Speicher. Das kann man in solch einem Modell mit Exceptions abfangen. Oder nicht?
Hehe, vor allem, wenn man ein Objekt discarden will, braucht man ja offensichtlich noch mindestens eine Referenz, sonst koennte man dem System ja nicht sagen, _was_ man discarden will ;)
Die tatsächliche Referenz ist ja nur ein Eintrag in einer Tabelle. Ein Flag NO_ACCESS in dieser Tabelle pro Referenz wäre dann schon das Discarden. Wenn dann der Garbage Collector damit arbeiten würde, wäre doch alles in Butter.

Re: Your daily dose of WTF featuring: Programming 2005-12-05 19:35
MoKrates
Hehe, vor allem, wenn man ein Objekt discarden will, braucht man ja offensichtlich noch mindestens eine Referenz, sonst koennte man dem System ja nicht sagen, _was_ man discarden will ;)
Die tatsächliche Referenz ist ja nur ein Eintrag in einer Tabelle. Ein Flag NO_ACCESS in dieser Tabelle pro Referenz wäre dann schon das Discarden. Wenn dann der Garbage Collector damit arbeiten würde, wäre doch alles in Butter.

Dann verstehst Du discarden als "foo = null;" schreiben, und Du willst die GC ihren Dienst machen lassen? Wo genau ist Dein Problem?

Mo

Re: Your daily dose of WTF featuring: Programming 2005-12-05 19:43
Wolf
Das weiss ich jetzt auch nicht mehr so genau. Guter Plan, das mit dem "foo=null;".

Re: Your daily dose of WTF featuring: Programming 2005-12-12 02:29
Gunnar
Die Klasse heißt Mensch.
Menschen haben die private Methode rülpsen.
Durch das private, wie wir es vorfinden, kann jeder Mensch jeden anderen rülpsen lassen, da ein Mensch sich selbst ja zum Rülpsen bringen kann.
Das ist doch schlecht!

Du hast die Klasse Mensch implementiert. Wenn du es nicht willst laesst kein Mensch einen anderen ruelpsen.. private ist dazu da, sich vor Code, auf den man keinen Einfluss hat zu schuetzen.


Re: Your daily dose of WTF featuring: Programming 2005-12-12 02:38
Wolf
Die Klasse heißt Mensch.
Menschen haben die private Methode rülpsen.
Durch das private, wie wir es vorfinden, kann jeder Mensch jeden anderen rülpsen lassen, da ein Mensch sich selbst ja zum Rülpsen bringen kann.
Das ist doch schlecht!

Du hast die Klasse Mensch implementiert. Wenn du es nicht willst laesst kein Mensch einen anderen ruelpsen.. private ist dazu da, sich vor Code, auf den man keinen Einfluss hat zu schuetzen.
Guten Morgen.

Wenn ich die Klasse Mensch so implementiere, dass kein Mensch einen anderen rülpsen lässt, dann kann er sich selbst nicht rülpsen lassen, außer jeder Mensch hat seine eigene Klasse. Da stellt sich dann die Sinnfrage.

Edit: Mit Deinem letzten Satz hast Du ja Recht, aber das Schlüsselwort, was ich hinter private zuerst vermutet hatte, gibt es offensichtlich nicht. Da private die geheimste Kapselung ist, ergibt sich eine Einschränkung in der Modellierung.

Re: Your daily dose of WTF featuring: Programming 2005-12-12 10:07
Slater
Wenn ich die Klasse Mensch so implementiere, dass kein Mensch einen anderen rülpsen lässt, dann kann er sich selbst nicht rülpsen lassen, außer jeder Mensch hat seine eigene Klasse. Da stellt sich dann die Sinnfrage.
naja,
public class Mensch { private void lache() { } public void tueDiesUndDas() { .. if (froehlich) { lache(); } .. } } geht ja wohl und da kann sich jeder Mensch nur selber zum lachen bringen (nach Aufruf von außen, sind ja keine Threads..)

du meinst wohl: sobald ein Mensch die Referenz auf einen anderen Menschen in der Hand hat kann er auch diesen zum lachen bringen,

das Problem bleibt, ja, ist aber nicht übermäßig tragisch wenn man nur aufpasst,
das als Einschränkung zu bezeichnen.., nun gut, kann man so sehen

Re: Your daily dose of WTF featuring: Programming 2006-01-16 10:22
Anonymer User
Hier noch eine nette Spielerei mit Reflection. Dieser Code
java.lang.reflect.Field stringValue = String.class.getDeclaredField("value"); stringValue.setAccessible(true); final String sittingDuck = "sittingDuck!!!!!"; stringValue.set(sittingDuck, "hastaLaVistaBaby".toCharArray()); System.out.println("sittingDuck!!!!!");gibt keineswegs "sittingDuck!!!!!" aus.

Man sollte sich durch final, private und co. eben keine Sicherheit vorspiegeln lassen, meist sind sie eher Hilflinien für die Modellierung (dass man auch dabei über die Umsetzung in der Java Spec diskutieren kann sei unbestritten).

Bessere Sicherheit gibt es erst, wenn man die JVM ausdrücklich weiter absichert. Hierzu reicht es aber eben nicht aus, dass man diese nur von innen sichert, so ein Angreifer die VM auch von ausserhalb angreifen kann. Eine Absicherung durch den Compiler reicht erst recht nicht, da man den Bytecode auch anders erzeugen und manipulieren kann.

Frühere Fassungen von Jython erlaubten es einem auch ohne Probleme auf beliebige private Felder zuzugreifen. Mittlerweile muss man dass durch einen Registryeintrag erlauben.

LEIFer

Re: Your daily dose of WTF featuring: Programming 2006-01-16 20:50
Nigel Menzel
Das ist schon klar, aber was soll ich mit dem Schlüsselwort, wenn ich es ohne Weiteres generisch umgehen kann? Das ist dann doch keine wirkliche Kapselung mehr!
Vielleicht habe ich ja etwas übersehen, aber so wirklich generisch scheint mir dein Beispiel nicht zu sein. Schließlich ist es auf diese Weise nicht möglich beliebige private Attribute irgendeiner Klasse zu manipulieren. Es ist nur möglich Attribute zu von Klassen zu manipulieren, für die es Methoden in der Art von setzeAnderesA() gibt.

Dieses Verhalten von private mag komisch erscheinen, ist aber durchaus nützlich und sinnvoll. Die Implementation von Copy-Construktoren oder dem Comparable Interface werden so sauberer. Ansonsten könnte man gezwungen sein, Attribute über das öffentliche Klasseninterface zugreifbar zu machen, die dort nichts zu suchen haben.

Darüber hinaus darf man private und protected nicht als Sicherheitsmaßnahmen missverstehen. Es gilt nicht bestimmte Attribute vor dem Zugriff von Außen zu schützen, diese Qualifier dienen der Strukturierung von Programmen und der Ausbildung von Interfaces. Jedem Java-Programmierer ist klar was private bedeutet und dass man dieses nicht zu umgehen hat, ob es nun möglich ist, oder nicht.

Re: Your daily dose of WTF featuring: Programming 2006-01-16 21:05
Wolf
Vielleicht habe ich ja etwas übersehen, aber so wirklich generisch scheint mir dein Beispiel nicht zu sein.
Meine Idee war in dem Posting, dass es einen Weg gibt, auch ohne die benötigte Methode den Wert zu verändern, ich habe aber keinen gefunden. Das Beispiel selbst war offensichtlich nicht generisch.
Jedem Java-Programmierer ist klar was private bedeutet und dass man dieses nicht zu umgehen hat, ob es nun möglich ist, oder nicht.
Das sei natürlich unbestritten.