# Ist Java gar nicht sooo objektorientiert??!



## MrWhite (8. Sep 2011)

Habe ich gerade gelesen in einer Diskussion:

"What you statement is a common misbelief yielded by Sun's successful agenda as promoting Java as the defacto-OOP standard as a response to OOP being hyped as the silverbullet in our industry. The core aspects of OOP are encapsulation and polymorphism, both of which are optional in Java, building classes with public fields or type relationships against final classes for example break them. Java is just C++ minus all the rope to hang yourself with. Java is *class*-based, which is not inherently *object*-oriented. Compare it to Io, Smalltalk, Ruby or Objective-C".

Was will uns der User damit sagen? Ist für ihn nur dynamischer Polymorphismus wahres OOP? Hat er eine sehr eigenwillige Definition von Objektorientierung? Oder spinnt der Typ einfach nur und spielt Buzzword Bingo um die Kontrahenten aus der Diskussion zu kicken?

Ich kenne leider Smalltalk oder Objective C nicht, gibt es da einen fundamentalen Unterschied?


----------



## Marco13 (8. Sep 2011)

Es wurde mal ein Test gemacht. Ich hab's nur noch grob in Erinnerung, aber einigen Studenten in den USA wurden Zitate vorgelegt. Einige von ehemaligen US-Präsidenten, und andere von "Klassenfeinden" (Hitler, Marx oder sonstwem). Die Verfasser der Zitate wurden teilweise richtig angegeben, teilweise wurde behauptet, das Zitat stamme von jemandem aus der anderen Gruppe. Die Zustimmung der Studenten zu den Zitaten hing nicht maßgeblich davon ab, WAS die Zitate aussagten, sondern davon, WER als Autor der Zitats angegeben wurde.

Man kann mit Java objektorientiert Programmieren, oder notfalls auch mit C (ohne ++). Man kann mit Smalltalk oder Eiffel prozedural programmieren, und sicher auch mit Ruby. Dass verschiedene Paradigmen in den jeweiligen Sprachen leichter umzusetzen, einzuhalten oder zu torpedieren sind, mag aber stimmen.


----------



## Gregorrr (8. Sep 2011)

Also Unterschiede in der Umsetzung, wie das objektorientierte Paradigma umgesetzt wurde gibt es schon. Java ist halt liberaler bei der Umsetzung. Einige Punkte sind:


 Primitive sind keine Objekte in Java. Das ist in Ruby, Python, Smalltalk anders. 
 Encapsulation: In Ruby kann mit nur mittels Methoden auf die Attribute eines Objekts zugreifen. Java erlaubt öffentliche Felder. [Allerdings kann man ja mittels Meta-Programmierung doch wieder darauf zugreifen]
 Finale Klassen unterbinden weiteres Ableiten.
Naja, spinnen tut er nicht. Er hat halt eine sehr feste Meinung. Dieser muss man sich nicht anschließen. Man darf sich selber seine Meinung bilden. Was ist ein OOP Standard, wer definiert ihn? Sicherlich kann man dem Autor widersprechen.

Auf den ersten Blick könnte man sagen, dass einige Sprachen OOP "besser" umgesetzt haben. Das tut aber nichts zur Sache, welche Sprache am meisten für OOP eingesetzt wird. Wie mein Vorposter schon richtig gesagt hat, kommt es darauf an, wie man in einer Sprache programmiert.

Das beste, was der Autor erreicht, ist dass man mal selber nachdenkt, wie genau die Programmiersprachen ihre Ziel umsetzen.


----------



## bygones (9. Sep 2011)

Gregorrr hat gesagt.:


> Finale Klassen unterbinden weiteres Ableiten.


Das ist auch gut so, nur weil eine Klasse in einer OOP Sprache ableitbar sein kann, muss man dies nicht foerdern. Vererbung ist eins der missverstandenen Probleme von OOP. Man sollte jede Klasse, die nicht explizit fuer Vererbung gedacht ist immer final machen.
Das seh ich nicht als Argument fuer "nicht oop" an.

Wenn man es ganz hart sehen will ist die Moeglichkeit [c]static[/c] zu haben ein "nicht oop" Argument, static programmierung ist prozedual und unterbindet oop


----------



## Landei (9. Sep 2011)

Ich würde der Aussage zustimmen, dass Java nicht vollständig OO ist, aber aus anderen Gründen:

- primitive Datentypen, Sonderbehandlung von Arrays
- statische Variabeln und Methoden (im Prinzip das Äquivalent zu globalen Variablen und Methoden in prozeduralen Sprachen)


----------



## asdasdasd (9. Sep 2011)

Landei hat gesagt.:


> Ich würde der Aussage zustimmen, dass Java nicht vollständig OO ist, aber aus anderen Gründen:
> 
> - primitive Datentypen, Sonderbehandlung von Arrays
> - statische Variabeln und Methoden (im Prinzip das Äquivalent zu globalen Variablen und Methoden in prozeduralen Sprachen)



Das kann ich in Smalltalk aber scheinbar auch machen. Da gibt es zwar kein static keyword, aber dafür class-side methods/members. 

Es bleibt also nur das Problem der primitive types.


----------



## asdasdasd (9. Sep 2011)

Hmm, naja, in Smalltalk ist die Klasse aber selbst ein first class citizen (also ein objekt) und kann deswegen wieder methoden haben. Das ist wohl etwas reiner als in Java. Also die Instanz von der Definition kann anscheinend Methoden haben.


----------



## schalentier (9. Sep 2011)

Ich wuerd mich hier weitestgehen der Definition aus der Wikipedia anschliessen. Dort wird unterschieden zwischen "pure OO languages" und Sprachen, mit denen man objektorientiert Programmieren kann. Bei reinen OO Sprachen ist _alles_ ein Objekt (es gibt also keine primitiven Typen, auch Klassen sind Objekte, etc). Dann koennen natuerlich auch Klassen Methoden haben - aber das hat nix mit dem static-Keyword von Java zu tun, was ja bekanntermassen einfach nur Murks ist. 

Das Vererbung missbraucht werden kann stimmt. Aber daraus den Schluss zu ziehen, dann alle Klassen final zu machen (ausser solche, von denen man explizit ableiten koennen soll; also nur abstrakte Klassen?) gefaellt mir aber nicht. Nichts ist nerviger, als eine Klasse, deren Verhalten man fuer einen speziellen Fall veraendern moechte, die final ist. Der Entwickler der Klasse kann ja gar nicht wissen, wie ich diese Klasse benutzen moechte. In meinen Augen kann final OOP kaputt machen. 

Ich kann jedem Java-Entwickler nur empfehlen, mal einen genaueren Blick auf eine solche "pure OO language" zu werfen. Dann programmiert man auch in Java ganz anders ;-) Mein Tipp ist Ruby. Hat ne einfache Syntax, kein kompliziertes Typsystem und einige sehr schoene OO Features.

Edit: Hat zwar nicht direkt was mit dem Topic zu tun, trotzdem ein sehr schoener Link: GOF Patterns in Ruby


----------



## bygones (10. Sep 2011)

schalentier hat gesagt.:


> Das Vererbung missbraucht werden kann stimmt. Aber daraus den Schluss zu ziehen, dann alle Klassen final zu machen (ausser solche, von denen man explizit ableiten koennen soll; also nur abstrakte Klassen?) gefaellt mir aber nicht. Nichts ist nerviger, als eine Klasse, deren Verhalten man fuer einen speziellen Fall veraendern moechte, die final ist. Der Entwickler der Klasse kann ja gar nicht wissen, wie ich diese Klasse benutzen moechte. In meinen Augen kann final OOP kaputt machen.


Der Entwickler soll auch nicht seine Klassen so entwickeln wie du sie vielleicht nutzen willst, du sollst eine Klasse so nutzen, wie sie designed wurde.
Ein final signalisiert eindeutig die Intension ob eine Klasse fuer Vererbung bereitgestellt wird oder nicht. Ein final wegzunehmen ist im nachhinein moeglich. Ein final hinzufuegen nicht. 
Ausserdem soll man nicht alle Klassen final machen, sondern eben die, die nicht zur Vererbung bestimmt sind. Und das sollte jeder API Entwickler wissen.
Vor allem wenn man in den Bereich der Immutable objects geht ist final ein entscheidender Aspekt.


----------



## mvitz (10. Sep 2011)

Zu dem Thema bezügliche final Klassen (und da ist auch noch viel mehr drin) kann ich http://www.amazon.de/Practical-API-...9739/ref=sr_1_1?ie=UTF8&qid=1315647660&sr=8-1 empfehlen. Da ist groß und breit erklärt, wieso es für eine *API* Sinn macht, so oft wie möglich final zu nutzen, um eine Weiterentwicklung ohne das brechen bisheriger Versionen zu ermöglichen. (Übrigens ist das Buch imho auch für nicht API-Entwickler sehr interessant).


----------



## schalentier (10. Sep 2011)

Gibts da ne Kurzfassung zum Thema final? Ich bin noch nicht ueberzeugt, weil bisher niemand ein Argument gebracht hat, warum ich all meine Klassen final machen soll, wenn man nicht explizit von diesen Ableiten koennen soll. Wie kann ich das entscheiden? Woher weiss ich, dass eine Ableitung nicht doch vielleicht irgendwann sinnvoll sein koennte?

Das einzige hier genannte Argument, man kann dann mit Ableitungen Schabernack treiben, lass ich nicht gelten - denn demnach muesste man noch so einige Sprachfeatures abschaffen. Man kann als Entwickler alles irgendwie missbrauchen. 

Zudem behindert mich das beim Schreiben von Tests. Da mach ich mir oft mal eine abgeleitete anonyme Klasse, die ein paar "teure" Methoden mit Stubs ersetzt. Da braucht man auch nicht immer gleich mit EasyMock & Co anfangen. 

Ausserdem frag ich mich grad, wie wir jetzt von OOP auf das Schreiben von APIs gekommen sind ;-)


----------



## bygones (10. Sep 2011)

schalentier hat gesagt.:


> Gibts da ne Kurzfassung zum Thema final? Ich bin noch nicht ueberzeugt, weil bisher niemand ein Argument gebracht hat, warum ich all meine Klassen final machen soll, wenn man nicht explizit von diesen Ableiten koennen soll. Wie kann ich das entscheiden? Woher weiss ich, dass eine Ableitung nicht doch vielleicht irgendwann sinnvoll sein koennte?


genau deine letzte Frage ist die entscheidende... wenn du eine klasse final machst kannst du durch das einfach streichen von final deine Klasse immer spaeter fuer vererbung oeffnen. Hast du kein final kannst du das nicht mehr rueckgaengig machen, wenn es API ist.
Jede Klasse die ableitbar ist, kann in ihren Unterklassen moegliche Logiken die in der Oberklasse gedacht sind aushebeln, missbrauchen oder einfach falsch verstehen. 



schalentier hat gesagt.:


> Das einzige hier genannte Argument, man kann dann mit Ableitungen Schabernack treiben, lass ich nicht gelten - denn demnach muesste man noch so einige Sprachfeatures abschaffen. Man kann als Entwickler alles irgendwie missbrauchen.


Es geht nicht primaer darum zu verhindern, dass jemand Schabernack treibt, sondern um die klarheit fuer was eine Klasse da ist und welche Moeglichkeiten einem bieten. Zb sollte man ebenso in einer zur Vererbung freien Klasse manche Methoden final erklaeren, wenn man eben klar stellen will, welchen Umfang die Subklassen haben koennen. Fuer den vererber soll klar sein, welche Logiken er manipulieren kann, und welche nicht.



schalentier hat gesagt.:


> Zudem behindert mich das beim Schreiben von Tests. Da mach ich mir oft mal eine abgeleitete anonyme Klasse, die ein paar "teure" Methoden mit Stubs ersetzt. Da braucht man auch nicht immer gleich mit EasyMock & Co anfangen.


das liegt aber dann an deiner allgemeinen struktur und nicht am final.
Deine Klassen sollten nur mit Schnittstellen arbeiten. Die Implementierungen sind dann moegl. final Klassen. D.h. wenn du dann deine Implementierung testest bekommt diese die Schnittstellen. Entweder per Dummies, Stubs oder Spies oder was auch immer. 
Andere Strukturen, die deine final Klasse nutzen, sollten das nicht und nur ueber die Schnittstelle arbeiten.
Somit ist final kein Argument gegen Test



schalentier hat gesagt.:


> Ausserdem frag ich mich grad, wie wir jetzt von OOP auf das Schreiben von APIs gekommen sind ;-)


hehe - is Gregorrs schuld


----------



## Marco13 (10. Sep 2011)

Nur ein kurzer Link-Einwurf: Die Frage von schalentier hängt wohl mit dem Open/closed principle - Wikipedia, the free encyclopedia zusammen. Ich finde auch, dass das Nachteile haben kann, aber vielleicht auch nur "vordergründige", die durch globalere und nicht unmittelbar erkennbare Vorteile ausgeglichen werden... Wie so viele Regeln und Best Practices.... (Nur als suggestivbeispiel: "Alle Fields private zu machen ist doch blöd, da muss man immer setter und getter schreiben und aufrufen..." - ja, im ersten Moment blöd, aber es gibt halt Gründe, warum alles andere ein no-go ist...)


----------



## mvitz (10. Sep 2011)

Irgendwo hatte ich mal ein nettes Beispiel, wo ohne final, jemand eine Subklasse erstellt hatte und nach einer Änderung in der Superklasse (die dort Sinn machte und auch richtig war), funktionierte die abgeleitete Klasse nicht mehr.

Habe aber gerade nachgeschaut und in "Effective Java 2nd Ed." Item 17: Design and document for inheritance or else prohibit it, gibts folgendes Beispiel:


```
public class Super {
  public Super() {
    overrideMe();
  }
  public void overrideMe() {}
}
```


```
public class Sub extends Super {
  private final Date date;
  public Sub() {
    date = new Date();
  }
  @Override pbulic void overrideMe() {
    System.out.println(date.toString());
  }
}
```
Hier hätte wenigstens die Methode overrideMe als final deklariert werden müssen. Und das kann eigentlich mit allen Methoden passieren, die man selber aufruft. Aus diesem Grund müssen eigentlich alle Methoden, die in der eigenen Klasse aufgerufen werden als final deklariert werden.

Edit: Dazu kommt natürlich auch, wer von den Klassen überhaupt ableiten kann. Wenn man ein rein internes Projekt hat, wo die Klassen nur innerhalb eines Teams verwendet werden, dann ist die Wahrscheinlichkeit, dass dort Schindluder getrieben wird eher gering. Allerdings spricht dann auch nichts dagegen erst mal alles final zu machen. Wenn man dann doch ne Subklasse braucht, kann man das final ja einfach wegnehmen. Bezüglich testen, entweder man nimmt in der Tat ein Framework mit dem man auch final Klassen extenden kann oder man hat schon vorher einen Denkfehler. Subklasse fürs testen deutet imho zu 90% auf einen Fehler im Design hin, der über DI oder das einführen eines Interfaces (welches dann an der Stelle Sinn macht) zu beheben ist.


----------



## mvitz (10. Sep 2011)

Ha, hab nen Beispiel gefunden  ( http://www.cas.mcmaster.ca/~emil/publications/fragile/ecoop98.pdf )


```
public class Bag {
    private final List<Character> chars = new LinkedList<Character>();
    public void add(char character) {
        chars.add(character);
    }
    public void addAll(Bag bag) {
        for (char character : bag.chars) {
            add(character);
        }
    }
    public int cardinality() {
        return chars.size();
    }
}
```


```
public class CountingBag extends Bag {
    private int n = 0;
    @Override public void add(char character) {
        n++;
        super.add(character);
    }
    @Override public int cardinality() {
        return n;
    }
}
```
Wenn man jetzt aus Performancegründen später die Klasse folgendermaßen ändert:

```
...
    public void addAll(Bag bag) {
        chars.addAll(bag.chars);
    }
...
```
Dann funktioniert, wie von Geisterhand der CountingBag nicht mehr, aus diesem Grunde, müsste man entweder die Methode add final machen, oder eben direkt die ganze Klasse (dann müsste der CountingBag Komposition verwenden und die Performanceänderung würde nichts ändern)


----------



## schalentier (10. Sep 2011)

Ich versteh das Beispiel nicht. Wo ist dort ein Problem? Wieso sollte man eine Methode "overrideMe" final machen? Das ergibt doch (selbst in einem Beispiel) absolut keinen Sinn??

Ich glaube wir sind in der Diskussion an einen Punkt gelangt, wo man nicht mehr sinnvoll weiterkommt ;-) Ich versteh, was ihr meint, hab da aber ne andere Meinung zu. Ich bin jemand, der damit leben kann, dass mein Programm, was eine API Version 2.0 benutzt, nach dem Update auf Version 3.0 teilweise nicht mehr funktioniert. Klar, das ist nicht schoen, aber so ist das (Programmierer-) Leben. 

Ich geh das lieber pragmatisch vor: Updaten auf neue Version und Testsuiten laufen lassen. Dann sollte es knallen und ich muss die Probleme halt fixen. 

Ich bleib dabei, final schraenkt die Objektorientiertheit ein, da ich niemandem vorschreiben moechte, wie er meine Klassen verwendet. Wenn dieser jemand Murks damit macht, ist das sein Problem und er wird es schnell feststellen. 

Aber vermutlich haengt das mit meinem Ausflug durch die Rubywelt zusammen: Dort kann man an bestehende Klassen im Nachhinein Methoden ranhaengen (man "oeffnet" die Klasse). Oder bestehende Methoden sogar ersetzen. Auch nen Typsystem gibt nicht und ich habs noch nicht vermisst. Einzige Bedingung, um damit auch groessere Projekte erfolgreich zu beenden, sind verdammt viele automatische Tests.

Aber ich werd das besagte Kapitel im Effektive Java Buch mal durchlesen.


----------



## mvitz (10. Sep 2011)

Naja, wie du an dem Beispiel oben sehen kannst, reicht dann aber auch bereits eine kleine Änderung (für die würde ich z.B. anstelle von 2.0 -> 3.0, eher -> Version 2.1 nutzen), dazu führen, dass Dinge nicht mehr gehen.

Und gerade Java ist ja was Rückwärtskompabilität angeht sehr penibel, was auch für die meisten Bibliotheken gilt.


----------

