Klassen immutable + nicht instanziierbar

escoo

Mitglied
Hallo,
da ich zZ für meine Prüfung in Java lerne, bin ich gerade auf eine Prüfungsfrage gestoßen, wo ich nicht weiter komme. Ich hab schon alles mögliche abgesucht, und immer nur das gleiche gefunden, was auf diese Frage nicht ganz so passt, deswegen versuche ich es hier.

Und zwar lautet die Frage:

Sie sollen folgende Hierarchie abbilden: CD -> Medium <- Buch (CD und Buch erbt von Medium)
Jedes Medium soll als Attribut ... und ... haben. Medium soll nicht instanziiert werden können und immutable sein.

a) Schreiben Sie die Klasse Medium mit den Vorgaben, den get und set Methoden und einem geeigneten Wert-Konstruktor, eine toString Methode usw.

Nun zum Problem:
Meines Wissens kann eine Klasse nicht instanziiert werden, wenn sie abstract ist.
Meines Wissens erreicht man, dass eine Klasse immutable ist, indem man keine setter setzt, oder die Klasse final macht.

Aber wie erreiche ich beides? Ich muss setter setzen, kann die Klasse aber nicht final und abstract gleichzeitig machen, und nach langem Suchen bin ich auch auf nichts anderes gestoßen.

Vielen Dank schonmal im Voraus 🙂

mfg
 
Zuletzt bearbeitet von einem Moderator:
Zu einer Klasse können immer Objekte instanziiert werden, es sei denn, es wird in jedem ihrer Konstruktoren eine Exception geworfen. Eine Instanz einer Subklasse ist auch die Instanz der Basisklasse.

Eine Klasse kann nicht immutable sein, wenn sie nicht final ist.

Kurz gesagt: Die Aufgabenstellung ist unmöglich zu erfüllen. Umso besser, dann hat man weniger zu tun. 🙂
 
Von abstrakten Klassen können soweit ich weiß keine Objekte erzeugt werden 🙂
Das das nicht lösbar ist, hab ich mir schon fast gedacht, mich hats nur gewundert, dass sowas in der Prüfung gefragt wird.

Danke 🙂
 
Meines Wissens kann eine Klasse nicht instanziiert werden, wenn sie abstract ist.
Richtig. Aber wo ist das Problem? Du hast ja die beiden Klassen die von Medium ableiten und nicht abstract sind.

Meines Wissens erreicht man, dass eine Klasse immutable ist, indem man keine setter setzt, oder die Klasse final macht.
Stimmt nicht ganz. Die Klasse final machen führt nur dazu dass du nichtmehr von der Klasse ableiten kannst. Immutable bedeutet dass sich das Objekt nach dem Erstellen nichtmehr ändert, das erreichst du z.b. indem du die Attribute final machst (und aufpasst dass die Attribute an sich auch immutable sind).
 
Von abstrakten Klassen können soweit ich weiß keine Objekte erzeugt werden 🙂
Nicht direkt von dieser Klasse, aber von Subklassen.

Java:
abstract class A {}
class B extends A {}

A a = new A() {}; // anonyme Klasse, erbt von A
B b = new B();
A a2 = b; // geht

System.out.println(a instanceof A); // true
System.out.println(b instanceof A); // true
System.out.println(a2 instanceof A); // true
 
Stimmt nicht ganz. Die Klasse final machen führt nur dazu dass du nichtmehr von der Klasse ableiten kannst. Immutable bedeutet dass sich das Objekt nach dem Erstellen nichtmehr ändert.
einer Klasse ist von außen nicht gut anzusehen, ob Methoden überschrieben wurden,
wenn getName() durch Subklasse verschiendene Werte liefert, wie soll man das dann noch als immutable ansehen?
wenigstens müssten alternativ wohl alle Methoden, die Zustandsinformationen liefern, auch hashCode() usw., final sein,
Attribute privat, wenn nicht gleich besser final
 
Also lösbar ist das schon. Abstrakte Klassen lassen sich anonym instanzieren, solange sie einen öffentlichen Konstruktor haben. Die Klasse Medium muss also schon mal einen geschützten Konstruktor (protected) anbieten. CD und Buch benötigen dann Konstruktoren, mit welchen sich die die unveränderlichen Daten übgeben lassen. Sollen CD und Buch ebenfalls nicht instanzierbar sein, benötigen sie ebenfalls geschützte Konstruktoren und müssten über eine Factory instanziert werden. Hier könnten dann evtl. auch geschützte Setter zum Einsatz kommen.
 
escoo hat gesagt.:
Medium soll nicht instanziiert werden können...
Mache sie abstract. Ist ja schon gesagt worden.
escoo hat gesagt.:
...und immutable sein
Ein Objekt ist immutable, wenn sich sein Zustand nach Erzeugung nicht ändern lässt. Zum Zustand eines Objektes tragen alle seine Instanzvariablen bei. D.h. diese dürfen nach Erzeugung nicht mehr änderbar sein. Dafür gibt es zwei Möglichkeiten:
- Mache die Instanzvariablen final (Nicht die Klasse! Bitte nicht verwechseln!).
- Mache die Instanzvariablen private und stelle keine Methoden zur Verfügung, die sie ändern (also setter weglassen).
SlaterB hat gesagt.:
getName() durch Subklasse verschiendene Werte liefert, wie soll man das dann noch als immutable ansehen?
Wenn jeder Aufruf der Methode auf einer Instanz jedes Mal den gleichen Wert zurück liefert ist diese Instanz/Objekt immutable.

Anhand Deines Beispiels wäre folgender Code denkbar:
Java:
abstract class Medium {

  private final String name;

  Medium(String name) {
    this.name = name;
  }

  // Hier könnte final davor, um ein Überschreigen dieser Methode zu verhindern
  // Das würde dann auch SlaterB's Definition von immutable sicherstellen
  public String getName() {
    return this.name;
  }
}

public class CD {

  public CD(String name) {
    super(name);
  }

  // N' büschn Polymorphismus, nur so als Beispiel
  // Bei gettern eher unüblich,.... denke ich zumindest
  public String getName() {
    return "CD: " + super.getName();
  }

}

public class Buch{

  private final int seitenZahl;

  public Buch(String name, int seitenZahl) {
    super(name);
    this.seitenZahl = seitenZahl;
  }
 
   // getName wird hier nicht überschrieben,
   // uns reicht das Verhalten der Klasse Medium

  public int getSeitenZahl() {

    return this.seitenZahl;

  }
}

P.S. Den Teil der Aufgabe mit den settern hab ich auch nicht verstanden. Das ist in meinen Augen entweder Nonsense oder der Aufgabensteller wollte Euch bewusst in die Irre führen, um zu sehen, ob ihr immutable verstanden habt.
 
Zuletzt bearbeitet von einem Moderator:
Wenn jeder Aufruf der Methode auf einer Instanz jedes Mal den gleichen Wert zurück liefert ist diese Instanz/Objekt immutable.
ich meinte dass die getName()-Methode der Subklasse nicht konstant einen abweichenden Namen zurückgibt, sondern wirklich verschiedene je nach Zeitpunkt

der Zustand eines Objektes ist wirklich normalerweise durch die Attribute dargestellt,
viel wichtiger im Betrieb ist doch aber die Sicht für Aufrufer, also das was die Methoden draus machen
In some cases, an object is considered immutable even if some internally used attributes change but the object's state appears to be unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

Immutable object - Wikipedia, the free encyclopedia
 
ich meinte dass die getName()-Methode der Subklasse nicht konstant einen abweichenden Namen zurückgibt, sondern wirklich verschiedene je nach Zeitpunkt.
Das wäre kein Immutable. Dein gepostetes Zitat bezieht sich evtl. auf Objekte wie z.B. String. Bei dieser werden z.B. beim Aufruf von subString Kindinstanzen mit identischem Chararray jedoch veränderten Stringpointern erzeugt und zurückgegeben. Diese Kindinstanzen aber sind wieder enbenso immutable, wie der Elternstring selber.
Bedeutet: Immutables dürfen sich intern verändern, diese Änderungen aber nicht nach draussen tragen. Mit dem Überschreiben von Methoden hat das nichts zu tun.
 
Zuletzt bearbeitet von einem Moderator:
nur um nochmal zu verdeutlichen was ich meinte:
Java:
public class Test {
    public static void main(String[] args)  {
        Medium m = new CD();
        System.out.println(m.getName()); // name0
        System.out.println(m.getName()); // name1
    }

}

abstract class Medium {

    public String getName()  {
        return "name"; // reichlich konstant
    }
}
class CD extends Medium {
    int count;
    public String getName()  {
        return "name"+count++; // nicht konstant
    }
}
Medium ist eine Klasse ohne Attribute, man könnte meinen immutable, und doch liefern zwei Aufrufe an Medium verschiedenes,
das halte ich für einen bedeutenden Widerspruch zur Behauptung, Medium wäre immutable
 
Ah ok, das mit dem final class hab ich wohl falsch verstanden.

Und das mit den Attributen final machen hab ich mir auch gedacht, das Problem war dabei halt nur, dass dadurch ja die Setter und der Konstruktor nicht mehr funktioniert. Und da ich beides brauche, ist mir diese Lösung von vornherein weggefallen.
 
Es reicht auch, die Attribute private zu machen und keine Setter zu implementieren, die diese ändern könnten

Wenn man erreichen will, dass eine in einer subclass überschriebene Methode nichts anderes zurück gibt, könnte man diese Methode final machen:

final methods

The final method can be declare as follows:

public final String convertCurrency()

The final method can't be override in a subclass.
Final Methods - Java Tutorials
 
escoo hat gesagt.:
Und das mit den Attributen final machen hab ich mir auch gedacht, das Problem war dabei halt nur, dass dadurch ja die Setter und der Konstruktor nicht mehr funktioniert. Und da ich beides brauche, ist mir diese Lösung von vornherein weggefallen.
Doch! Mit den Konstruktoren geht das, hab ich in meinem letzten Post doch ein Beispiel für gegeben. Das mit den Settern geht natürlich nicht, aber da haben wir ja eh schon gemerkt, dass es entweder Blödsinn oder bewusste Irreführung durch den Aufgabensteller war.
 
@SlaterB: CD ist in deinem Beispiel auch keineswegs Immutable. Laut Aufgabenstellung soll Medium immutable sein, das bedeutet aber nicht, dass es auch Kindklassen sein müssen.
[EDIT]
Das mit den Settern geht natürlich nicht, aber da haben wir ja eh schon gemerkt, dass es entweder Blödsinn oder bewusste Irreführung durch den Aufgabensteller war.
Meinen Post mit der Factory übersehen? Dort kann man durchaus geschützte Setter implementieren, legitim ist das auch. Ob es aber sinnvoll ist, ist 'ne andere Frage. Aber gesehen hab' ich das schon oft.[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:
SlaterB hat gesagt.:
Java:
class CD extends Medium {
    int count;
    public String getName()  {
        return "name"+count++; // nicht konstant
    }
}
Interessanter Hinweis, Slater! Mir dämmert, dass ich da in Effective Java ein Kapitel zu "Designing Classes for Inheritance" gelesen habe, wo genau solche Probleme dargestellt waren...

Für den TO: D.h. die Methode getName() müsste in Medium final deklariert sein, um diesen Fall auszuschließen.
 
Zuletzt bearbeitet von einem Moderator:
Meinen Post mit der Factory übersehen? Dort kann man durchaus geschützte Setter implementieren, legitim ist das auch. Ob es aber sinnvoll ist, ist 'ne andere Frage. Aber gesehen hab' ich das schon oft.
Ich bezog das auf MEINE Variante mit den finalen Instanzvariablen. Da kann man ja keine Setter implementieren. Außerdem würde ich eine Klasse, die Code enthält, der den Status einer Instanz verändert, nicht als immutable bezeichnen. Egal, wie weit zugreifbar dieser Code ist.

Ich halte den Setter-Teil der Aufgabe nach wie vor für eine bewusste Irreführung oder Schludrigkeit des Aufgabenstellers.
 
Zuletzt bearbeitet von einem Moderator:
Java:
class ImmutableClass
{
  private int value;

  ImmutableClass(int newValue)
  {
    value = newValue;
  }

  public int getValue()
  {
    return value;
  }

  public ImmutableClass setValue(int value)
  {
    return new ImmutableClass(value);
  }
}

So bleibt die Klasse immutabale, bekommt aber einen setter. Ich finde diese Variante nicht sonderlich schick, da ein Setter seinen Sinn nicht erfüllt, sondern eher eine derive Methode ist.
 
Ich halte den Setter-Teil der Aufgabe nach wie vor für eine bewusste Irreführung oder Schludrigkeit des Aufgabenstellers.
Joa... vllt. hat er sich ja verdrückt ausgekehrt :lol:. Man kann halt nur drüber spekulieren. Ebenso, wie man darüber spekulieren kann, ob Buch bzw. CD ebenfalls immutable sein sollen.
So bleibt die Klasse immutabale, bekommt aber einen setter. Ich finde diese Variante nicht sonderlich schick, da ein Setter seinen Sinn nicht erfüllt, sondern eher eine derive Methode ist.
Dazu würde ich sagen, das der Name der Methode schlicht schlecht gewählt wurde. Über öffentliche Setter in Immutables kann man wirklich nur lachen (Siehe Schandros Beitrag).
 
Zuletzt bearbeitet von einem Moderator:
Java:
class ImmutableClass
{
  private int value;

  ImmutableClass(int newValue)
  {
    value = newValue;
  }

  public int getValue()
  {
    return value;
  }

  public ImmutableClass setValue(int value)
  {
    return new ImmutableClass(value);
  }
}

Leicht verändert:
Java:
abstract class ImmutableClass
{
  private final int value;

  protected ImmutableClass(int newValue)
  {
    value = newValue;
  }

  public final int getValue()
  {
    return value;
  }

  public void setValue(int value)
  {
    throw new RuntimeException();
  }
}

Würde dann der Aufgabestellung entsprechen, oder?
 
Java:
public void setValue(int value)
{
    throw new RuntimeException();
}
Würde dann der Aufgabestellung entsprechen, oder?
Was für ein Käse! Aber wenn schon, dann wenigstens anwenderfreundlich mit richtigem Exception-Typ und aussagefähiger Fehlermeldung:
Java:
public void setValue(int value)
{
    throw new UnsupportedOperationException("Medium is immutable.");
}
P.S. Und um den Blödsinn perfekt zu machen, setz noch ein
Code:
@Deprecated
über die Methode und mach sie private.
 
Zuletzt bearbeitet von einem Moderator:
@Deprecated ist wohl überflüssig. Das wäre halt ein Kompromiss zwischen beiden 😉 So abwegig erscheint mir das nicht
 
@Deprecated ist wohl überflüssig. Das wäre halt ein Kompromiss zwischen beiden 😉 So abwegig erscheint mir das nicht
Ähhh... abwägig? In einem Immutable einen öffentlichen Setter zu implementieren, der nur 'ne Exception schmeisst, ist wohl noch nicht abwägig genug? Ausserdem würd's keinen Sinn machen, denn wer [c]setValue()[/c] in einem Immutable derartig implementiert, nutzt auch Deprecated-APIs. Das ist aber alles Thema der Witzecke.
 

Zurück
Oben