Twitter: @grzegg
Kategoria: java, Tagi: - - - .

Java [07] – Zmienne cz. III: rzutowanie i konwersja typów

Rodzaj zmiennej używanej w obliczeniach może wpływać na wynik, który otrzymamy. Na szczęście istnieją mechanizmy pozwalające zmieniać typy danych tak aby je dostosować do potrzeb.

Ta strona jest częścią materiałów do kursu “Programowanie w Javie z elementami bioinformatyki dla poczatkujących”. Pozostałe materiały znajdziesz tutaj

Rzutowanie i konwersja typów

Wróćmy jeszcze do programu, który pisaliśmy w poprzedniej lekcji, dotyczącego fikcyjnej studentki. W napisanym kodzie można jeszcze dopatrzeć się kolejnego zdublowania używanej wartości. Przecież utworzyliśmy zmienną rokStudiow, czy nie można by jej użyć, zamiast wpisywać ręcznie liczbę 3.0? Takie rozwiązanie miałoby sens, jeśli mielibyśmy umieszczać dane dla różnych studentów na różnych latach studiów, za każdym razem tę samą wartość trzeba by wpisywać dwukrotnie. Szkoda czasu! Sprawa jednak jest nieco bardziej skomplikowana, niż by się mogło wydawać na pierwszy rzut oka. Prosta zamiana 3.0 na rokStudiow sprawi, że znów otrzymamy wynik 12.0 zamiast 12.666…. Zauważ, że rokStudiow jest zmienną typu byte, czyli przechowuje liczby całkowite. Nie można po prostu dopisać kropki z zerem na końcu nazwy zmiennej, trzeba jakoś zmienić liczbę całkowitą na liczbę typu double. Ten proces nazywa się rzutowaniem (ang. casting) i możemy go przeprowadzić np. tak:


double sredniaLiczbaKursow=(kursy1Rok+kursy2Rok+kursy3Rok)/(double)rokStudiow;

Jak widać, przed nazwą zmiennej została umieszczona w nawiasie nazwa typu danych na jaki ma się zmienić przechowywana w zmiennej liczba. Teraz wartość zmiennej rokStudiow najpierw jest zamieniana na typ double a następnie jest używana w obliczeniach.

Do podobnej zmiany typu zmiennej mieliśmy do czynienia wcześniej, tyle że w sposób niejawny. Kiedy obliczane było działanie (kursy1Rok+kursy2Rok+kursy3Rok)/3.0 także zmienne typu całkowitego były zmieniane w liczby zmiennoprzecinkowe a wynik, który też był liczbą zmiennoprzecinkową, był przekazywany do zmiennej (albo instrukcji wyświetlającej wynik). Mieliśmy w tym przypadku do czynienia z konwersją typów (ang. type conversion). Ogólna zasada rządząca konwersją jest taka, że Java stara się dopasować typ liczb tak aby nie stracić informacji. Czyli np. jeśli jedna z liczb jest typu int a druga double to obie są traktowane jak double, jeśli jedna jest typu int a druga long to int jest zmieniany w long itp. Można to podsumować zestawem reguł:

  1. Wartości byte, short oraz char są konwertowane podczas obliczeń do typu int
  2. Jeśli jeden z operandów jest typu long to całe działanie (pozostałe wartości) jest konwertowanie do long
  3. Jeśli jeden z operandów jest typu float to całość jest konwertowana do float
  4. Jeśli jeden z operandów jest typu double to całość jest konwertowana do double

Zwróć uwagę, że jeśli wykonamy kod (bez konwersji byte na double):


double sredniaLiczbaKursow = (kursy1Rok+kursy2Rok+kursy3Rok)/rokStudiow;
System.out.println("Średnia liczba kursów: " + sredniaLiczbaKursow);

to otrzymamy wynik 12.0 (o czym wspomniałem wcześniej). Otrzymana liczba jest błędna, brak jest wartości ułamkowej „666…”, choć jest przecież liczbą zmiennoprzecinkową. Stało się tak dlatego, że najpierw zostaje obliczony wynik działania, który jest liczbą całkowitą, a więc nie posiada informacji o części ułamkowej, a dopiero później jest konwertowany i przypisany do zmiennej typu double. Jak widać przy konwersji danych na programistę czeka sporo pułapek.

Należy też wspomnieć o sytuacji odwrotnej, kiedy staramy się przypisać wartości o typie wyższym do zmiennych o typie niższym.
Próba skompilowania kodu:


double r = 2.0;
double pi = 3.14;
int obwodKola = 2 * pi * r;

skończy się niepowodzeniem, netBeans zresztą ostrzega nas, że mamy do czynienia z typami niekompatybilnymi. Żeby program się skompilował, należy oczywiście zmienić zmienną na typ double.

Inny możliwy typ błędu ilustruje poniższy przykład:


byte liczba1 = 10;
byte liczba2 = 5;
byte wynik = liczba1 + liczba2;

Próba kompilacji zaowocuje błędem, w NetBeans trzecia linia zostaje podkreślona i zostaniemy poinformowani, że: „_incompatible types: possible lossy conversion from int to byte_”. Przeczytawszy ten komunikat możesz poczuć się zdezorientowany, przecież wszystkie zmienne użyte w działaniu są typu byte, skąd więc wziął się tu typ int?

Spójrz jeszcze raz na pierwszą z powyższych reguł. Mówi ona, że wartości byte, short oraz char są konwertowane podczas obliczeń do typu int. Nie ma tu warunku, że jeden z operandów ma być typu int. Wymienione typy są więc automatycznie konwertowanie w trakcie działań do typu int, nawet jeśli żaden z nich nie jest tego typu i co więcej, nawet, gdy rezultat działania nie przekracza dozwolonego zakresu (dla byte jest to (przypominam) –128 do 127. Program będzie działał jeśli zmienna wynik będzie typu int (lub wyższego) albo jeśli przeprowadzimy rzutowanie wyniku na typ byte:


byte wynik = (byte)(liczba1 + liczba2);

Ta strona jest częścią materiałów do kursu “Programowanie w Javie z elementami bioinformatyki dla poczatkujących”. Pozostałe materiały znajdziesz tutaj

5 komentarzy Java [07] – Zmienne cz. III: rzutowanie i konwersja typów

  • zxcv

    Chyba powinno być „albo jeśli przeprowadzimy rzutowanie wyniku na typ byte”.

  • tetkris

    Czemu to wyrzuca błędy, co tu jest źle ?

    float duk = 3.42;
    float ren = 4.21;

    float jak = duk/ren;

    Czyżby floaty służyły do czegoś innego niż double (wiem tylko że double mogą zapisywać więcej miejsc po przecinku).

  • Slonzok

    „Spójrz jeszcze raz na pierwszą z powyższych reguł. Mówi ona, że wartości byte, short oraz char są konwertowane podczas obliczeń do typu int. Nie ma tu warunku, że jeden z operandów ma być typu int. Wymienione typy są więc automatycznie konwertowanie w trakcie działań do typu int, nawet jeśli żaden z nich nie jest tego typu i co więcej, nawet, gdy rezultat działania nie przekracza dozwolonego zakresu (dla byte jest to (przypominam) –128 do 127. Program będzie działał jeśli zmienna wynik będzie typu int (lub wyższego) albo jeśli przeprowadzimy rzutowanie wyniku na typ byte:”

    W takim razie może zadam jednak głupie pytanie, ale cóż. Po co używać w takim razie typów byte i short skoro kompilator i tak to ignoruje i konwertuje do int??

Leave a Reply