wtorek, 6 maja 2008

Java Killers #005

Witam w kolejnym cyklu z serii Java Killers, dziś sprawdzimy naszą wiedzę z zakresu prostego operatora ?. Wszyscy znamy ta konstrukcje prawda? Dla przypomnienia wygląda ona tak:

a = b ? c : d

, gdzie zależnie od wartości zmiennej b, zmienna a przyjmuje wartość c lub d. Znane? Znane! No to przejdźmy zatem do dzisiejszego przykładu:


1 package javakillers.part005;
2
3 /**
4 * @author pawel
5 */
6 public class Main
7 {
8 public static void main(String[] args)
9 {
10 Main m = new Main();
11 m.run();
12 }
13 public void run()
14 {
15 Object o = true ? new Integer(0) : new Double(0.0);
16 System.out.println("Klasa " + o.getClass().getName() + ", wartość " + o.toString());
17 }
18 }
19


Odpowiedzi standardowo do wyboru są cztery:

A) Błąd kompilacji
B) Klasa java.lang.Integer, wartość 0
C) Klasa java.lang.Double, wartość 0.0
D) Klasa java.lang.Object, wartość java.lang.Object@87816d //przy czym @87816d może mieć dowolną inną wartość

Zanim przeczytasz rozwiązanie, spróbuj pomyśleć nad odpowiedzią.



No to jak, gotowi? Otóż poprawna odpowiedź to C) Klasa java.lang.Double, wartość 0.0 . Tak tak moi mili Object o = true ? new Integer(0) : new Double(0.0) zwróci nam obiekty typu Double. Pytanie "ale czemu?" pozostaje wciąż otwarte, gdyż na logikę widzimy, że referencja powina wskazywać na obiekt typu Integer!

Żeby zrozumieć dokładnie co stało się za naszymi plecami w czasie wykonywania kodu, należy zajrzeć do specyfikacji języka Java, a konkretnie do rozdziału '15.25 Conditional Operator ?', gdzie czytamy, że:

" (...) if the second and third operands have types that are convertible to numeric types, then (...) binary numeric promotion is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion and value set conversion."

Czy widzicie już zło jakie czai się za tym zdaniem? Kompilator orientuje się, że zwrócony wynik będzie zawsze typem numerycznym (Integer lub Double). W czasie działania programu dokonuje unboxingu do wartości prymitywnych, następuje promocja typu (w tym wypadku z int'a na double) i ponowny boxing do obiektu już typu Double a nie Integer!
Żeby to lepiej zobrazować, zmieńmy w naszym kodzie new Integer(0) na new Integer(1)


13 public void run()
14 {
15 Object o = true ? new Integer(1) : new Double(0.0);

Po uruchomieniu dostaniemy odpowiedź Klasa java.lang.Double, wartość 1.0. Widzicie co się dzieje?

Co ciekawe jeśli uruchomicie poniższe przykłady pod Eclipsem, wyskoczy Wam błąd kompilacji! Eclipse używa swojego własnego kompilatora (innego niż javac dostarczony z JDK), który jak tylko zobaczy Object o = true ? new Integer(1) : new Double(0.0); krzyczy "Ja nic nie wiem, ja nic nie chce, ja nic nie umiem!!!" Na innych IDE, takich jak Netbeans czy IntelliJ IDEA, kompilacja przebiega poprawnie, a wyniki działania programów są takie jak opisane powyżej.

Teraz się przyznać, ile osób znało poprawną odpowiedź? :)



19 komentarzy:

Anonimowy pisze...

dobre ;)

Anonimowy pisze...

Ja nie znałem poprawnej odpowiedzi, ale zrobiłem tak jak napisałem w moim ostatnim komentarzu dotyczącym odcinka #004 - czyli zaznaczyłem najmniej (według mnie) logiczną odpowiedź. No i wyszło C, w końcu jest 1:4 jeszcze dla Ciebie ;-)

Paweł Szulc pisze...

hehe bede musial zatem dawac wiecej tych nieloginczych odpowiedz do wyboru :) ale punkt dla Ciebie i to sie liczy!

Adam Kędziora pisze...

znowu nie wiedziałem 2:3 dla ciebie - ale tym razem przesadziłeś - szczerze wątpie, by ktokolwiek z marszu znal uzasadnienie odpowiedzi ;] - trochę zamienia się to w tym momencie na sztukę dla sztuki ;]

Paweł Szulc pisze...

@Adam Kędziora: Wiesz, nie do końca. Zawsze wydawalo mi sie ze opartor ? ma zwrocic jedna z dwoch moziwosci, czyli majac a = b ? c : d, spodziewam sie obiektu c lub d.

tu okazuje sie ze moge dostac trzeci obiekt. nie chodzi juz o to ze wartosc bedzie ta sama, ja mowie ze referncje chodziby sa inne. i wez to potem zdebugguj :)

nie chce w tych javakillersach robic sztuki dla sztuki, raczej probje wyszukiwac jakies myki, ewnt haczyki ktre keidys moga przyprawic o bol glowy.

jk podawane w malych dawka powoduje ze nawet jesli czegos takiego nie znales, to z pewnoscia zapamietasz :)

thread pisze...

@Paweł Artykuł i pomysł spoko. Tak trzymaj!
Mam pewne zastrzeżenie do akapitu traktującym o rzekomych błędach w Eclipsie. Nie wiem dokładnie jakiego i jak skonfigurowanego środowiska używasz. U mnie pod linuxem i Eclipse 3.3.2 wszystko działa OK. Może to banalne, ale może nie masz poprawnie ustawionych zmiennych środowiskowych JAVA_HOME, PATH. Nie wiem jak jest w Windowsie, ale pod linuxem polecam jeszcze ustawić poprawne dowiązanie "java" w /etc/alternatives/
To tyle. Pozdrawiam.

Anonimowy pisze...

bardzo dobre i ciekawe!

tak trzymać!

p.s.
nie, nie wiedziałem dlaczego :P

Paweł Szulc pisze...

@thread: blad zwiazany z eclipsem zglosil mi kolega ktremu pokazywalem najnowszego JK#005. nie sprawdzilemw sumie tego bo nawet nie mam eclispa zainstlowanego na dysku (uzywam tylko netbeansa i idea).

zrobie researchw temacie i zupdateuje watek
dzieki za info!

Anonimowy pisze...

Pytania same w sobie ciekawe i intrygujace, tylko widze juz kolejna zagwozdke zywcem wzieta z java puzzlers, przydalaby sie chociaz informacja skad bierzesz takie zagadki...

mzdz pisze...

Kozacka zagadka! Nie wiedziałem, ale JK#004 było proste, więc póki co 3:2 dla mnie ;)

Paweł Szulc pisze...

anonimowy: tej zagadki nie wzialem z java puzzlers, a stad: http://forum.java.sun.com/thread.jspa?threadID=5246823&start=0&start=0

trudno mi sie odniesc do tego czy bylo to na java puzzlers poniewaz ksizki java puzzlers nie czytalem - widzlem tylko jakis ich wystep na video.google.

do java puzzlers dalem linka w pierwszym poscie dlatego ze wiem ze taka ksiazka jest i pewnie soie kiedys ja kupie.

masz jednak racje ze zrodla warto podawac i nie chodiz tu o prawa autorskie czy cos :) tylko warto zeby ludzie mogli czytac dalej i poszerzac swoja wiedze. Wiec bede teraz bede pod koniec tekstow podawal zrodla, mozliwe ze do poprzednich artykułow zrobie updaty i zrodla tez pworzucam

dzieki za koment!

Paweł Szulc pisze...

@mzdz: cóż, jesli wygrywasz to tylko dobrze swiadczy o Tobie :)

Adam Kędziora pisze...

nie wiem, może to dla tego, ze zawsze uznawałem operator ? za chory wymysł - zrobienie tego samego ifem nie zadziała wolniej, a będzie o niebo bardziej czytelne - naprawdę nigdy nie mogłem zrozumieć dlaczego designerzy javy wrzucili ten operator - taki on, hmmmm, niskopoziomowy ;P.

olektrolek pisze...

ojj,
ja tam znajduje pozytek w operatorze ?. na przykład wypisując cos do loga - wszystko fajnie w jwendej linii. a z ifami juz mialbys conajmniej kilka.

a do formatowania uzywaj dodatkowych spacji, nawiasow - kod bedzie czytelny.

Adam Kędziora pisze...

szczerze, co będzie bardziej czytelne :

if (n>1) {
procesor = new smp();
} else {
procesor = new single();
};

czy

procesor = (n>1) ? procesor = new smp() : procesor = new single();

(tu prawdopodobnie w ogóle się linia zawinie, więc będzie totalna porażka)

procesor = (n>1) ?
procesor = new smp() :
procesor = new single();

już nie mówiąc o tym, ze pierwszą konstrukcję zrozumie absolutnie każdy (nie tylko ktoś kto używa java).

Adam Kędziora pisze...

hmmmm, wcięcia wcięło, różnica sie jeszcze pogłębia :P

Paweł Szulc pisze...

Adam czy przypadkiem konstrukacja nie bedzie wygladac tak:

procesor = (n>1) ? new smp() : new single();

:)

agata pisze...

'@adam' Przecież operator "?" istnieje nie tylko w Javie ;-)
Ja tam osobiscie go lubie ale staram sie nie naduzywac np w ten sposob: cos = wyr() ? ( wyr2() ? 1: 2) : 3

pozdrawiam:)

Michał Trzcinka pisze...

Muszę przyznać, że wgniotło mnie w fotel ;) Ogólnie bardzo ciekawa seria Java Killers, pozdrawiam ;)