Java Quiz

Die Klasse „Example“ ist public, und müßte in einer eigenen Datei liegen. Wenn man das „public“ wegnimmt, erscheint, wie erwartet
error: cannot find symbol: ExampleA
error: cannot find symbol: ExampleB

Also: Meeep :smiley:

Das geht doch ohne public?

[spoiler]```//-----------------------------------------------------------------------------
class Example {
static ExampleA get(){ return new ExampleA(); }
}

class ExampleA extends ExampleB{ }

class ExampleB {{ System.out.println(“geht”); }}
//-----------------------------------------------------------------------------

public class Temp {
public static void main(final String[] args) {
final Example<?> example = null;
final ExampleA a = example.get();
final ExampleB b = example.get();
}
}```[/spoiler]

Gruß
Fancy

Sehe ich auch so. Mein Lösungsvorschlag, diesmal in der eingebetteten Form:

Temp.java
[spoiler]```//-----------------------------------------------------------------------------
class Example {
public static U get() {
return null;
}
}

class ExampleA {
}

class ExampleB {
}
//-----------------------------------------------------------------------------

public class Temp {
public static void main(String[] args)
{
Example<?> example = null;
ExampleA a = example.get();
ExampleB b = example.get();
}
}```[/spoiler]

OK, @Fancy und @cmrudolph haben die Aufgabe gelöst.

Allerdings wurde (natürlich) das ausgenutzt, was ich schon befürchtet hatte: Es gab zu viele Freiheitsgrade.

Deswegen ein neues Quiz: Füge zwischen den //--- Strichen das ein, was notwendig ist, damit das ganze compiliert, ohne Exceptions durchläuft, und am Ende „Done“ ausgibt:

//-----------------------------------------------------------------------------
...
//-----------------------------------------------------------------------------

public class Temp 
{
    public static void main(String[] args)
    {
        Example<?> example = Example.create();
        ExampleA a = example.get();
        ExampleB b = example.get();
        
        if (ExampleA.class.isAssignableFrom(ExampleB.class))
        {
            throw new RuntimeException("No");
        }
        if (ExampleB.class.isAssignableFrom(ExampleA.class))
        {
            throw new RuntimeException("No");
        }
        Integer i = a.getInteger();
        String s = b.getString();
        System.out.println("Done");
    }
}

(Ich will, wie man sich schon denken können sollte, auf einen bestimmten Punkt raus - aber das „Spiel“, die gestellte Aufgabe durch (andere) „Tricks“ zu lösen, gehört ja irgendwie dazu :smiley: )

Vermutlich nicht das worauf Du hinaus wolltest. :wink:

[spoiler]```//-----------------------------------------------------------------------------
class Example {

private static boolean flag;

static Example<?> create() {
    return new Example<Object>();
}

<U> U get() {
    flag = !flag;
    if (flag)
        return (U) new ExampleA();
    else
        return (U) new ExampleB();
}

}

class ExampleA {
Integer getInteger() {
return 42;
}
}

class ExampleB {
String getString() {
return „life, the universe and everything“;
}
}
//-----------------------------------------------------------------------------

public class Temp {

public static void main(final String[] args) {
    final Example<?> example = Example.create();
    final ExampleA a = example.get();
    final ExampleB b = example.get();
   
    if (ExampleA.class.isAssignableFrom(ExampleB.class))
        throw new RuntimeException("No");

    if (ExampleB.class.isAssignableFrom(ExampleA.class))
        throw new RuntimeException("No");

    final Integer i = a.getInteger();
    final String s = b.getString();
    System.out.println("Done");
}

}```[/spoiler]

Gruß
Fancy

Ganz sicher nicht das, worauf du hinaus wolltest :o) :
[spoiler]```//-----------------------------------------------------------------------------
class Example {
public static U get() {
return null;
}

public static Example<?> create() {
    System.out.println("Done");
    System.exit(0);
    return null;
}

}

class ExampleA {
public Integer getInteger() {
return 0;
}
}

class ExampleB {
public String getString() {
return “”;
}
}
//-----------------------------------------------------------------------------

public class Temp {
public static void main(String[] args)
{
Example<?> example = Example.create();
ExampleA a = example.get();
ExampleB b = example.get();

    if (ExampleA.class.isAssignableFrom(ExampleB.class))
    {
        throw new RuntimeException("No");
    }
    if (ExampleB.class.isAssignableFrom(ExampleA.class))
    {
        throw new RuntimeException("No");
    }
    Integer i = a.getInteger();
    String s = b.getString();
    System.out.println("Done");
}

}```[/spoiler]

@cmrudolph Nicht ganz :wink: @Fancy : Gut, eine weitere Verschärfung: Ohne unchecked casts :smiley:

@Marco13 : immer noch nicht das, was du meintest, oder?
Erfüllt aber alle bisher aufgestellten Regeln :stuck_out_tongue:

[spoiler]```//-----------------------------------------------------------------------------
class Example {
public CommonExample get() {
return new CommonExample();
}

public static Example<?> create() {
    return new Example<>();
}

}

interface ExampleA {
Integer getInteger();
}

interface ExampleB {
String getString();
}

class CommonExample implements ExampleA, ExampleB{
public Integer getInteger() {
return 0;
}

public String getString() {
    return "";
}

}
//-----------------------------------------------------------------------------

public class Temp {
public static void main(String[] args)
{
Example<?> example = Example.create();
ExampleA a = example.get();
ExampleB b = example.get();

    if (ExampleA.class.isAssignableFrom(ExampleB.class))
    {
        throw new RuntimeException("No");
    }
    if (ExampleB.class.isAssignableFrom(ExampleA.class))
    {
        throw new RuntimeException("No");
    }
    Integer i = a.getInteger();
    String s = b.getString();
    System.out.println("Done");
}

}```[/spoiler]

Aber irgendwie ist diese Lösung ja langweilig.

Ja, das ist es.

Und zugegeben, es IST langweilig - aber hauptsächlich, weil der eigentliche Kernpunkt durch die Einschränkungen und Workarounds irgendwie verloren gegangen ist. Ich wollte eigentlich nur darauf raus, dass bei sowas wie

class Example<T extends ExampleA & ExampleB>
{
    T get()
    {
        return null;
    }
}

die Abfragen

        ExampleA a = example.get();
        ExampleB b = example.get();

beide möglich sind, auch wenn der Parameter lokal nur als <?> definiert ist, und die beiden Rückgabetypen (!) nichts miteinander zu tun haben…

So war das mit dem langweilig gar nicht gemeint. Ich finde sie in Bezug auf die anderen Lösungen “langweilig”, weil es eine ist, die in produktivem Code auch tatsächlich so auftauchen könnte und daher “gewöhnlich” ist.

An meinem Code hat man gesehen, dass das (im Gegensatz zu der von mir erwarteten Lösung) nicht unmittelbar mit Generics zu tun hat. Darauf gekommen bin ich, weil ich nach einer Konstruktion gesucht habe, bei der die Klassen zwar in der selben Vererbungshierarchie sind, aber nichts miteinander zu tun haben. Das funktioniert nur bei Mehrfachvererbung, wenn sich die Klassen in parallelen Strängen befinden. Und daraus folgt unmittelbar, dass es sich bei den Typen um Interfaces handeln muss.

Was passiert, wenn man den folgenden Code laufen lässt?

        Matcher matcher = pattern.matcher(":foo");
        if (matcher.find()) {
            System.out.println("Ha!");
        }

[SPOILER]Zum Herumspielen:


import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DoubleQuestionMark {

    public static void main(String[] args) {
        singleTest();
        fullTests();
    }

    private static void singleTest() {
        Pattern pattern = Pattern.compile("( ??:foo)");
        Matcher matcher = pattern.matcher(":foo");
        if (matcher.find()) {
            System.out.println("Ha!");
        }
    }

    private static void fullTests() {
        List<String> regexes = new ArrayList<>();
        regexes.add("( ?:foo)");
        regexes.add("( ??:foo)");

        List<String> texts = new ArrayList<>();
        texts.add(":foo");
        texts.add(" :foo");
        texts.add("?:foo");
        texts.add(" ?:foo");

        for (String text : texts) {
            System.out.println("Text: [" + text + "]");
            for (String regex : regexes) {
                System.out.println("    regex: [" + regex + "]");
                Pattern pattern = Pattern.compile(regex);
                Matcher matcher = pattern.matcher(text);
                if (matcher.find()) {
                    System.out.println("        gefunden: [" + matcher.group(1) + "]");
                }
                else {
                    System.out.println("        nichts gefunden.");
                }
            }
        }
    }

}

[/SPOILER]

Hmm, mal sehen, ob’s richtig ist:
[spoiler]Die beiden Klammern der Regex bilden eine Capturing Group. Der String darf mit einem oder keinem Leerzeichen anfangen (?? ist ein relunctant Quantyfier “once or not at all”). Danach muss das String-Literal “:foo” kommen.
Ich würde also bei matcher.find() ein true erwarten und damit die Ausgabe von “Ha!”[/spoiler]

[spoiler]Stimmt. Ich war ein wenig verwirrt, dass das doppelte Fragezeichen erlaubt ist. “x?” steht ja auch schon für “ein oder kein x”.[/spoiler]

System.out.println((byte) (1.0/0));
System.out.println((short) (1.0/0));
System.out.println((int) (1.0/0));
System.out.println((long) (1.0/0));

Was ist die Ausgabe?

Gerade ein Projekt korrekturgelesen und irgendwas stimmte hinten und vorne nicht, hat mich heute den ganzen Tag gebraucht diese(n) Fehler im Projekt ausfindig zu machen.
Schöner Freitag!
Zu klein und nicht direkt nach vollziehbar.
Aber das will ich euch natürlich ersparen, deshalb hier mal eine extrahierte Variante die sich nicht über mehrere Methoden und Klassen verteilt.

Was ist die Ausgabe

		float countdown = 0f;
		float timer = 0f;
		int sleep = 20;
		double cstep = 0.020;

		boolean run = true;

		System.out.println(getTimeStamp() + " Sequence started");
		while (run) {
			try {
				Thread.sleep(sleep);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			if (countdown != timer) {
				System.out.println("out of sync");
			}
			if (countdown >= 10 && countdown == timer) {
				System.out.println("Ignite boosters and liftoff");
				run = false;
			}
			if (countdown == 4) {
				System.out.println("Start main engines");
			}
			if (countdown == 0) {
				System.out.println("t minus one-zero seconds, counting");
			}

			countdown += cstep;
			timer = timer + (float) cstep;
		}
		System.out.println(getTimeStamp() + " Sequence stopped");
	}```

Beim ersten Draufschauen würde ich sagen, dass die ==-Vergleiche da gröbster Unfug sind. Aber ob das gemeint ist?

Das ist teilweise mal richtig, das ist einer der Fehler im Code gewesen.
Es beginnt zwar bei 0 und die Zahl wird immer um 0,02 vergrößert, heißt aber nicht dass sie erwartungsgemäß irgendwann “4” wird oder eine andere Zahl die man erwarten würde.
float und double halt, weiß nicht jeder.

Was aber wenn ich sage dass die Ausgabe in der Konsole lautet:

- t minus one-zero seconds, counting
- out of sync
- Ignite boosters and liftoff
- Sequence stopped

Außer durch Zufall hätte ich den kleinen Fehler im Code wahrscheinlich nie gefunden.

Denn im Projekt bricht der Start zwar ab weil die Geräte der Rakete eine falsche Zeit Angabe haben obwohl um das selbe delta t erhöht wird.
Im Beispiel oben repräsentiert durch “out of sync”.
Okay, start wird abgebrochen und BUM die Rakete startet in der Simulation plötzlich trotzdem…

Geht es darum, dass
someFloat += someDouble
und
someFloat = someFloat + someDouble
nicht das gleiche ist? (Viel mehr bleibt wohl nicht mehr übrig…)

Genau, aber dann eben wieder nicht, nur manchmal.
In der Schleife werden die Beiden floats nach ein paar Iterationen Addition ungleich zueinander aber nach ein paar weiteren Iterationen der Addition haben sie wieder den gleichen Wert.

Zwei gleiche Zahlen werden also um den selben Wert erhöht, haben aber ein anderes Ergebniss und diese unterschiedlichen Zahlen werden wieder um den selben Wert erhöht und haben dann wieder das gleiche Ergebniss?!?

Nun, da müßte ich jetzt auch erst länger überlegen und mit-Tracen was er denn in der Schleife so macht … (und noch der sarkastische Hinweis: Nimm doch BigDecimal :smiley: )