Java Quiz

Also ich versteh das Betthupferl nicht… :frowning:
Die Fehlermeldung kann ich lesen, aber der Sinn, weshalb das nicht kompilieren sollte, will mir nicht in den Kopf. Kann mir da einer der Verständnisvollen erklären woran es liegt?

Es ging darum, dass es „fast unmöglich“ ist, das eigentliche Problem zu erkennen, selbst wenn man sich über das, was die Ursache für den Fehler ist, im Klaren ist (Funktion lub(T0, T1) entsprechend Chapter 15. Expressions :wink: ). Das eigentliche Problem IST ja gerade, dass man da anhand der Fehlermeldung etwas (er)kennt, was man nicht (er)kennen sollte…

Ok… dazu reicht mein derzeitiges Verständnis von den Java-Interna offensichtlich noch nicht aus…

*** Edit ***
@Marco13 : meintest du vielleicht http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25 statt den von dir geposteten Link?

Die Frage, die sich mir stellt ist: Warum löst der auf AbstractStringBuilder und nicht auf Appendable auf? Denn die Methode selbst wird ja eigentlich von Appendable eingeführt, und nicht von AbstractStringBuilder!? :confused:

Ok, wenn man sich den Abschnitt 15.25 durchliest, findet man heraus, dass man den zweiten “Otherwise”-Fall hat und landet dann beim von @Marco13 geposteten Kapitel 15.12.2.7.

Wie oben angedeutet, das ist schon ein ziemlich „krankes Artefakt“. GROB zusammengefasst (und ohne Gewähr :wink: ): Bei dem Ternären Operator ist (wenn die beiden letzten Operanden Objekte sind) der Rückgabetyp der „lowest upper bound“ (lub) der Typen der beiden Operanden (die Funktion, die da verlinkt ist). Sinngemäß bedeutet das wohl sowas wie
(b ? someFloat : someInteger) -> Ergibt eine 'Number'
(b ? someFloat : someString) -> Ergibt ein 'Comparable'
(und ich glaube immernoch, dass man das durch einen Diamanten irgendwie raushauen können müßte - nochmal drüber nachdenken…)

In diesem konkreten Fall sind die Typen ‚StringBuffer‘ und ‚StringBuilder‘. Deren „lowest upper bound“ ist die Klasse ‚AbstractStringBuilder‘, von der beide direkt erben (womit sie noch „lower“ als Appendable ist). D.h. der Typ des Ergebnisses dieses Ternären Operators ist ‚AbstractStringBuilder‘. Und das Problem hängt nun damit zusammen, dass diese Klasse nicht public ist…

Das würde auch nicht helfen, das Problem kommt erst „später“. :slight_smile:

[QUOTE=Landei]Richtig!

Oh, und als Betthupferl:

//Version 1
String s = (Math.random() > 0.5 ? new StringBuilder("Hi ") : new StringBuffer("Hello ")).append(" world!").toString();
System.out.println(s);

//Version 2
Appendable app = (Math.random() > 0.5 ? new StringBuilder("Hi ") : new StringBuffer("Hello ")).append(" world!");
System.out.println(app.toString());

Funktionieren beide Versionen?[/QUOTE]

Boah, ich hoffe ich treff die Beschreibung richtig …

Beide Varianten funktionieren nicht. Die erste Variante lässt sich schon gar nicht kompilieren, die zweite knallt zur Laufzeit.

Das Problem liegt in dem hier: (Math.random() > 0.5 ? new StringBuilder("Hi ") : new StringBuffer("Hello "))
Sowohl StringBuilder als auch StringBuffer sind Ableitungen von AbstractStringBuilder und beim ternären Ausdruck wird eben AbstractStringBuilder als Ergebnis erwartet, da nicht bekannt ist, ob nun StringBuilder oder StringBuffer geliefert werden. Das Problem scheint aber zu sein, dass AbstractStringBuilder package-private ist und „direkte“ Zugriffe darauf ja nicht funktionieren. Um beide Varianten funktionisfähig zu machen, muss man das Ergebnis des ternären Ausdrucks explizit zu Appendable castet. Dann muss aber die IOException von Appendable.append(String) verarbeitet werden. Dann funktioniert es aber auch.

Sieht dann so aus:

public class Foobar {
	public static void main(String[] args) throws IOException {
		// Version 1
		String s = ((Appendable)(Math.random() > 0.5 ? new StringBuilder("Hi ") : new StringBuffer("Hello "))).append(" world!").toString();
		System.out.println(s);

		// Version 2
		Appendable app = ((Appendable)(Math.random() > 0.5 ? new StringBuilder("Hi ") : new StringBuffer("Hello "))).append(" world!");
		System.out.println(app.toString());
	}
}

EDIT:
Mist, Marco war schneller :smiley:

Und ich glaube, hier vermischt sich grad was. Einige scheinen über das Rätsel vor dem Betthupferl zu sprechen und andere über das Betthupferl. Wird Zeit für ein neues Rätsel :smiley: Weiß aber keins :frowning:

Danke für die Erklärung!
Dabei ist dann wohl auch der Fakt relevant, dass die Methode toString in AbstractStringBuilder als abstrakt deklariert wurde und somit die Implementierung von Object überschreibt.

Edit: das ist deshalb nicht relevant, weil bereits der Zugriff auf die Klasse die Exception wirft.

[QUOTE=cmrudolph]Danke für die Erklärung!
Dabei ist dann wohl auch der Fakt relevant, dass die Methode toString in AbstractStringBuilder als abstrakt deklariert wurde und somit die Implementierung von Object überschreibt.[/QUOTE]

Ja, das hatte ich auch bemerkt. Wie Marco aber richtig sagt ist das primäre Problem die (Nicht-)Sichtbarkeit von AbstractStringBuilder. Aber klar, wenn diese Klasse sichtbar wäre, würde es aufgrund von toString() immer noch nicht klappen. :slight_smile:

Ne, also nach meinem Versuch das nachzubilden ist die toString-Methode vollkommen irrelevant, denn diese wird ja von der konkreten Instanz implementiert (Polymorphie, darum geht es ja auch, wenn man das Ergebnis des ternären Ausdrucks explizit zu Appendable castet). Die Nicht-Sichtbarkeit nach Außen hin ist das zentrale und einzige Problem.

public class Foobar {
	public static void main(String[] args) {
		Foo foo = Math.random() > .5 ? new Bar() : new Bar2();
		System.out.println(foo);
	}
}

abstract class Foo {
	@Override
	public abstract String toString();
}

class Bar extends Foo {
	@Override
	public String toString() {
		return Bar.class.getSimpleName();
	}
}

class Bar2 extends Foo {
	@Override
	public String toString() {
		return Bar2.class.getSimpleName();
	}
}

Huch. Was sagt man dazu. Wieder was gelernt. :slight_smile: Merci!

Hab etwas. Nicht schwierig, aber was solls:

Wir haben die Methode
public void doStuff( ? runnableComp)

Die Methode soll nur Objekte entgegennehmen die sowohl vom Typ JComponent sind, als auch das Interface Runnable implementieren*. Für falsche Parameter soll ein **Kompilerfehler **erzeugt werden. Wie muss die Signatur der Methode aussehen?

*) Mir egal, ob die Kombination Sinn macht. :stuck_out_tongue: Ist für die Aufgabe nicht relevant.

Mal sehen, wie gut ihr addieren könnt:

System.out.println(0610 + 0b10);

Aus dem Kopf sowas wie

public <T extends JComponent & Runnable> void doStuff(T runnableComp)

Damit kann man auch ziemlich kranke Sachen machen. Wirklich praktisch genutzt habe ich es zwar noch nicht, aber … es hat IMHO das Potential, für interessante Sachen genutzt zu werden…

*** Edit ***

Müßte 394 ergeben: 0610 (Oktal) = 664+18+0*1 = 384+8 = 392, und dann noch die binäre 2 dazu…

EDIT: Mit sowas wie
System.out.println(062l + 0b10);
ist’s fast noch gemeiner :smiley:

[QUOTE=Marco13]Aus dem Kopf sowas wie

public <T extends JComponent & Runnable> void doStuff(T runnableComp)

Damit kann man auch ziemlich kranke Sachen machen. Wirklich praktisch genutzt habe ich es zwar noch nicht, aber … es hat IMHO das Potential, für interessante Sachen genutzt zu werden…

*** Edit ***

Müßte 394 ergeben: 0610 (Oktal) = 664+18+0*1 = 384+8 = 392, und dann noch die binäre 2 dazu…

EDIT: Mit sowas wie
System.out.println(062l + 0b10);
ist’s fast noch gemeiner :D[/QUOTE]

Mist, für beides zu langsam :smiley:

Wie kommt man denn jetzt darauf die erste Zahl oktal zu betrachten?

Weil sie mit einer 0 beginnt. 0b is binär und 0x hexadezimal. Fallen aber sicherlich viele drauf rein :wink:

Oha. Und nochmal was gelernt. Hab ich noch nie gebraucht. :slight_smile:

Muss man aber aufpassen. 05 oder 0000000000005 ergibt zwar 5, könnte man also durchaus denken, dass es eine dezimale Zahl ist. Dennoch ist es eine Oktalzahl, was man auch bei 055 dann sieht, ergibt nämlich 45. Da ich aber davon ausgehe, dass man solche Scherze (gerade sowas wie 000000000005) nicht im Code finden wird, fällt das hoffentlich eher nicht so ins Gewicht.