Forum: PC-Programmierung Java-Quizfrage


von Claudio H. (bastelfinger)


Lesenswert?

Weil ich diesen Samstag arbeiten muss, hier eine kleine Quizfrage um 
euch zu quälen:
Kennt ihr einen Weg, wie man in Java auf uninitialisierte Attribute 
eines Objekts zugreifen kann? Bitte den Quellcode dazu posten. Ich kenne 
einen Weg, die Auflösung gibt es später.

Bitte kein google benutzen, sondern auf eigene Lösungen kommen!

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Alle Attribute werden per default inistialisiert (mit null oder je nach 
primitivem Typ vorgegebenem default).
Uninitialisierte (lokale) Variablen gehen nicht durch den Compiler... 
also wenn dann bitte ein Beispiel.
Oder meinst du das die Variablen den von dir vorgegeben (initial) Wert 
zum Zeitpunkt des Zugriffs noch nicht haben?
Das Phnomen hatte ich auch schon das ein oder andere mal, trotzdem sind 
die Variablen initialisiert (nur nicht mit dem Wert welchen man zunächst 
erwartet)

von Claudio H. (bastelfinger)


Lesenswert?

>Alle Attribute werden per default initialisiert (mit null oder je nach
>primitivem Typ vorgegebenem default).

Genau das meine ich, es gibt trotzdem eine Möglichkeit, VOR dieser 
Initialisierung auf ein Attribut zuzugreifen. Viel Spaß beim Nachdenken!

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Claudio H. schrieb:
>>Alle Attribute werden per default initialisiert (mit null oder je nach
>>primitivem Typ vorgegebenem default).
>
> Genau das meine ich, es gibt trotzdem eine Möglichkeit, VOR dieser
> Initialisierung auf ein Attribut zuzugreifen. Viel Spaß beim Nachdenken!
Und dann? Wie merkst du das dieser Zugriff wirklich unitilalisiert 
geschieht?
Und was soll das überhaupt bringen? (Wenn es nicht sogar von der VM 
Implementierung abhängig ist...)

von Claudio H. (bastelfinger)


Lesenswert?

Hey, das ganze ist eine Quizfrage, muss also keinen Nutzen haben. Man 
kann aber durch Zuweisung an eine Variable, die anschließend erst 
initialisiert wird, schöne Fehler einbauen. Also sollte man das schon im 
Hinterkopf behalten.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Aber eine Zuweisung welche danach überschrieben wird ist doch kein 
Zugriff auf eine uninitialisierte Variable, daher ja meine Frage wie du 
erkennst das du auf eine uninitialisierte Variable zugreifst...

von Claudio H. (bastelfinger)


Lesenswert?

Naja, du weisst ja, dass Java eine Reihenfolge der Initialisierung 
vorgibt, z.B. zunächst die static Attribute, dann der static Block, dann 
die Instanzattribute, dann werden die Konstruktoren aufgerufen, am 
Anfang jedes Konstruktors der super-Konstruktor usw.

Kannst du dich irgendwie in diese Reihenfolge reinhängen, und auf ein 
Attribut zugreifen, welches erst später initialisiert wird? Per meiner 
Definition ist dieser Zugriff dann uninitialisiert.

von Stephan M. (stephanm)


Lesenswert?

Claudio H. schrieb:
> Kennt ihr einen Weg, wie man in Java auf uninitialisierte Attribute
> eines Objekts zugreifen kann?

Per JNI, wenn man die "Lücke" zwischen AllocObject und 
CallNonvirtualVoidMethod ausnutzt. Was die JRE dazu sagt weiß ich zwar 
nicht, aber den Zugriff auf uninitialisierte Felder kann ich da bequem 
explizit hinschreiben ;-)

Stephan

von Stefan M. (Gast)


Lesenswert?

Das da gibt zunächst 0 aus, danach 42.
1
public class Quiz {
2
3
  private static final class DeepThought extends Supercomputer {
4
    
5
    int whatIsTheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything() {
6
      return theAnswer;
7
    }
8
    
9
    private int theAnswer = 42;
10
  }
11
  
12
  private static abstract class Supercomputer {
13
    
14
    public Supercomputer() {
15
      int theAnswer = whatIsTheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything();
16
      System.out.println(theAnswer);
17
    }
18
    
19
    abstract int whatIsTheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything();
20
  }
21
22
  
23
  public static void main(String[] args) {
24
    
25
    DeepThought deepThought = new DeepThought();
26
    
27
    int theAnswer = deepThought.whatIsTheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything();
28
    System.out.println(theAnswer);
29
  }
30
  
31
}

von Stefan M. (Gast)


Lesenswert?

Übrigens gibt es hier unterhaltsamere Rätsel präsentiert von Joshua 
Bloch höchstpersönlich.

http://video.google.com/videoplay?docid=9214177555401838409#

von Stephan M. (stephanm)


Lesenswert?

Stefan May schrieb:
> Das da gibt zunächst 0 aus, danach 42.

Claudio H. (Threadersteller) schrieb:
> Weil ich diesen Samstag arbeiten muss

Lass mich raten: Claudio musste nur deswegen Samstag arbeiten, weil ein 
durch ein derartiges Konstrukt entstandener Fehler dringend bereinigt 
werden musste...

Hier findet man ein bisschen Diskussion zum Verhalten von Java und von 
anderen Programmiersprachen in diesem Fall (der dritte Beitrag von oben 
erklärt das Verhalten des Codes von Stefan):

http://www.artima.com/forums/flat.jsp?forum=226&thread=113723

Ich persönlich finde übrigens das Verhalten von C++ besser, auch 
deswegen, weil ich es selbst erleben musste, dass das hier ausgenutzte 
Verhalten von Java zu schwer zu lokalisierenden, ekligen Fehlern führen 
kann. Gelegentlich findet man daher die Regel, dass Konstruktoren nur 
als "final" gekennzeichnete Methoden der eigenen Klasse aufrufen dürfen.

Stephan

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Läubi .. schrieb:
> Oder meinst du das die Variablen den von dir vorgegeben (initial) Wert
> zum Zeitpunkt des Zugriffs noch nicht haben?

Hatte ich doch oben schon geschrieben... Dieser Zugriff ist aber eben 
nicht uninitialisiert, sonder du bekommst (korrekterweise) 0 zurück, das 
dies nicht deinem erwarteten Wert (42) entspricht ist doch wieder etwas 
anderes.

Das Objekt oder die Variable wird schon initialisiert, nur dein davon 
abweichender Default wert wird erst zugewiesen wenn der Konstruktor 
durchlaufen wurde. Das ist ärgerlich wenn man es weiss aber durchaus ein 
vorhersehbares Verhalten.

@Stephan M.
Naja das Problem tritt nur auf wenn man mehrere Aufgaben im Kontruktor 
ausführt, was ich mittlerweile für mich persönlich als schlechten Stil 
deklariert habe

von Sven P. (Gast)


Lesenswert?

Na dann. Ist zwar kein Java, sondern Standard-C, aber trotzdem schön:
1
printf("%i", abs(INT_MIN));
2
/* Ausgabe: -2147483647 (negativ!) */
3
4
int *a;
5
int b[10];
6
puts( (a == &a) ? "1. gleich" : "1. ungleich" );
7
puts( (b == &b) ? "2. gleich" : "2. ungleich" );
8
9
10
/* Ausgabe: 1. gleich 2. ungleich */

Über letzteres bin ich auch schon böse gestolpert.

von Klaus W. (mfgkw)


Lesenswert?

1
klaus@a64a:~ > gcc -Wall t.c
2
t.c: In function ‘main’:
3
t.c:11: warning: comparison of distinct pointer types lacks a cast
4
t.c:12: warning: comparison of distinct pointer types lacks a cast
5
klaus@a64a:~ > ./a.out
6
1. ungleich
7
2. gleich

von Stefan M. (Gast)


Lesenswert?

Läubi Du hast natürlich recht, daß das kein Zugriff auf uninitialisierte 
Variablen ist. Der TO hat ja seine Definition von "uninitialisiert" 
wiedergegeben.

Und zu C++: Sowohl in Java als auch in C++ gibt es böse Fallen, die sich 
nur durch "Best Practices" umschiffen lassen. Nicht umsonst gibt es zu 
diesem Thema sowohl für C++ als auch Java diverse Bücher, die man 
gelesen haben sollte.

mfg, Stefan.

von Claudio H. (bastelfinger)


Lesenswert?

Smayfinger, du hast "meine" Lösung gefunden. Ich bin tatsächlich mal 
über dieses Verhalten gestolpert, auf meinem Entwicklungsrechner lief 
das wunderbar, der ContinuousIntegration Server hatte eine andere VM und 
ist abgestürzt.
Das Problem in meinem Fall war ein Framework, welches massiv auf dem 
"Template Method" Pattern aufgebaut hat, und mich dadurch zu diesem 
Ansatz gezwungen hat.


Hat noch jemand eine Quizfrage?

von Stefan M. (Gast)


Lesenswert?

Dieses Verhalten ist ganz klar definiert und ist ganz sicher "bad 
practice".

> Hat noch jemand eine Quizfrage?

Ja, ein ganzes Buch voll. Siehe Link zum Vortrag von Joshua Bloch.

von Claudio H. (bastelfinger)


Lesenswert?

>Dieses Verhalten ist ganz klar definiert und ist ganz sicher "bad
practice".

Wenn man allerdings den Attributen nicht im Konstruktor, sondern inline 
einen Wert zuweist, dann ist das Verhalten von VM zu VM unterschiedlich. 
Also glaube ich nicht, dass das SO genau definiert ist.

Dass es Bücher mit Quiz-Fragen gibt, ist mir schon klar, nur macht das 
Rätseln im Forum mehr Spaß!

von Sven P. (Gast)


Lesenswert?

Klaus Wachtler schrieb:
>
1
> klaus@a64a:~ > gcc -Wall t.c
2
> t.c: In function ‘main’:
3
> t.c:11: warning: comparison of distinct pointer types lacks a cast
4
> t.c:12: warning: comparison of distinct pointer types lacks a cast
5
> klaus@a64a:~ > ./a.out
6
> 1. ungleich
7
> 2. gleich
8
>

Ich schäme mich, hab ich doch glatt vertauscht... G

von Stefan M. (Gast)


Lesenswert?

Claudio Du irrst:

http://java.sun.com/docs/books/jls/third_edition/html/execution.html#44670

In Punkt 4 geht es um die Initialisierung der Instanz-Variablen. In 
§12.5 steht am Ende auch die Antwort auf Deine Quiz-Frage.


Mich würde interessieren, mit welchen VMs Du das unterschiedliche 
Verhalten beobachtet hast.


Und noch ein Puzzler hinterher (Achtung ist geklaut und nicht von mir):
1
public class Hamlet {
2
3
  public static void main(String[] args) {
4
    Random rnd = new Random();
5
    boolean toBe = rnd.nextBoolean();
6
    Number result = (toBe || !toBe) ? new Integer(3) : new Float(1);
7
    
8
    System.out.println(result);
9
  }
10
11
}

Was wird auf System.out ausgegeben?

 a) 3
 b) 1.0
 c) wirft eine Exception
 d) etwas total anderes

Hint: JLS §15.25

mfg, Stefan.

von Stefan M. (Gast)


Lesenswert?

Und ein C-Puzzler hinterher:
1
#include "stdio.h"
2
#define  e 3
3
#define  g (e/e)
4
#define  h ((g+e)/2)
5
#define  f (e-g-h)
6
#define  j (e*e-g)
7
#define k (j-h)
8
#define  l(x) tab2[x]/h
9
#define  m(n,a) ((n&(a))==(a))
10
11
long tab1[]={ 989L,5L,26L,0L,88319L,123L,0L,9367L };
12
int tab2[]={ 4,6,10,14,22,26,34,38,46,58,62,74,82,86 };
13
14
main(m1,s) char *s; {
15
    int a,q,c,d,o[k],n=(int)s;
16
    if(m1==1){ char q[2*j+f-g]; main(l(h+e)+h+e,q); printf(q); }
17
    else switch(m1-=h){
18
  case f:
19
      a=(q=(c=(d=g)<<g)<<g)<<g;
20
      return(m(n,a|c)|m(n,q)|m(n,a|d)|m(n,c|d));
21
  case h:
22
      for(a=f;a<j;++a)if(tab1[a]&&!(tab1[a]%((long)l(n))))return(a);
23
  case g:
24
      if(n<h)return(g);
25
      if(n<j){n-=g;c='D';o[f]=h;o[g]=f;}
26
      else{c='\r'-'\b';n-=j-g;o[f]=o[g]=g;}
27
      if((q=n)>=e)for(q=g<<g;q<n;++q)o[q]=o[q-h]+o[q-g]+c;
28
      return(o[q-g]%n+k-h);
29
  default:
30
      if(m1-=e) main(m1-g+e+h,s+g); else *(s+g)=f;
31
      for(*s=a=f;a<e;) *s=(*s<<e)|main(h+a++,(char *)m1);
32
  }
33
}

Was gibt das Program aus? Achtung, ebenfalls geklaut und leicht 
abgeändert, wegen Forum-Spamfilter.

mfg, Stefan.

von Robert S. (razer) Benutzerseite


Lesenswert?

Stefan May schrieb:
> Was wird auf System.out ausgegeben?
>
>  a) 3
>  b) 1.0
>  c) wirft eine Exception
>  d) etwas total anderes

d) nämlich 3.0


Kenn ich schon :)

von Stefan M. (Gast)


Lesenswert?

Genau wegen dem "Kenn ich schon"  ist das langweilig. :-P

von Stephan M. (stephanm)


Lesenswert?

Stefan May schrieb:
> Und ein C-Puzzler hinterher:

Jeder, der mal die Programme beim Obfuscated Perl Contest gesehen (oder 
gar zu verstehen versucht) hat, wird sowas NIE NIE NIE durch den 
Compiler jagen und dann ausführen, weil es umgefähr eine Bazillion 
Möglichkeiten gibt, ein 'system("rm -fr $HOME")' zu verstecken 8-)

Andererseits scheinen Compiler langsam aber sicher einzuholen, vgl. das 
Posting "danni - Apr 05, 2008 - 02:36 PM" / "Post subject: RE: Re: RE: 
operand out of range" auf 
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=61771&start=0

Das hat mich deutlich mehr erstaunt als diese ewigen Versuche, "hello, 
world!" möglichst kompliziert hinzuschreiben...

Stephan

von Claudio H. (bastelfinger)


Lesenswert?

smayfinger,
die JDKs waren Version 1.4.1, beide auf WindowsXP. Wenn man in der 
überschriebenen abstrakten Methode Werte an Attribute zugewiesen hat, 
gab es zur Laufzeit bei einem JDK eine Excpetion, das andere lief durch. 
Kann natürlich auch am Compiler gelegen haben.

von Stefan M. (Gast)


Lesenswert?

> gab es zur Laufzeit bei einem JDK eine Excpetion

Welche Exception war das genau?

In Java 1.4 und älter waren einige Patterns gebräuchlich, die nicht 
funktionierten. Zum Beispiel das double-checked-locking. In Java 1.5 
wurde daraufhin das Memory-Model gründlich poliert und klar definiert. 
In 1.4 war das Verhalten tatsächlich abhängig vom verwendeten Compiler 
und von der verwendeten JVM.

Von Angelika Langer gibt es einen netten Vortrag zum Java Memory Model, 
welcher wirklich sehenswert ist.

mfg, Stefan.

von Claudio H. (bastelfinger)


Lesenswert?

Die genaue Exception weiss ich nicht mehr, war aber vielleicht eine 
NullPointerException.

von Filter (Gast)


Lesenswert?

>die JDKs waren Version 1.4.1, beide auf WindowsXP. Wenn man in der
>überschriebenen abstrakten Methode Werte an Attribute zugewiesen hat,
>gab es zur Laufzeit bei einem JDK eine Excpetion, das andere lief durch.
>Kann natürlich auch am Compiler gelegen haben.

ich finde es lüstig wie die von Java gepriesene 
"Plattformunabhängigkeit"
von der Wirklichkeit eingeholt wird :)

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Filter schrieb:
>>die JDKs waren Version 1.4.1, beide auf WindowsXP. Wenn man in der
>>überschriebenen abstrakten Methode Werte an Attribute zugewiesen hat,
>>gab es zur Laufzeit bei einem JDK eine Excpetion, das andere lief durch.
>>Kann natürlich auch am Compiler gelegen haben.
>
> ich finde es lüstig wie die von Java gepriesene
> "Plattformunabhängigkeit"
> von der Wirklichkeit eingeholt wird :)
Ich finde es lustig wie Leute ohne Fundierte Kenntnisse sich über 
scheinbare Makel andere Leute Arbeit amüsieren...

Was hat bitte ein (möglicherweise) unterschiedliches Verhalten 
verschiedener JavaVM (IBM? Windows? Sun?) mit Plattformunabhänigkeit zu 
tun? Zumal beide auf WinXP liefen...

Zumal noch nicht mal der genaue Fehler reproduziert werden könnte, da 
Source + genauere Umgebung nicht (mehr) zur Verfügung stehen...

von Filter (Gast)


Lesenswert?

>> ich finde es lüstig wie die von Java gepriesene
>> "Plattformunabhängigkeit"
>> von der Wirklichkeit eingeholt wird :)

>Ich finde es lustig wie Leute ohne Fundierte Kenntnisse sich über
>scheinbare Makel andere Leute Arbeit amüsieren...

nett, dass du ohne mich zu kennen, als jemand ohne "fundierte 
Kenntnisse"
(und dann noch falsch geschrieben, bin heute mal so kleinlich :) 
hinstellst.

nein, ich vertrete die Meinung, dass eine komplexe Sache auch dann
komplex bleibt, wenn man ihr ein anderes Pelz überstopft.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.