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
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ł:
- Wartości
byte
,short
orazchar
są konwertowane podczas obliczeń do typuint
- Jeśli jeden z operandów jest typu
long
to całe działanie (pozostałe wartości) jest konwertowanie dolong
- Jeśli jeden z operandów jest typu
float
to całość jest konwertowana dofloat
- Jeśli jeden z operandów jest typu
double
to całość jest konwertowana dodouble
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
Chyba powinno być „albo jeśli przeprowadzimy rzutowanie wyniku na typ byte”.
Dziękuję za zwrócenie uwagi.
Pozdrawiam.
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).
float duk = (float) 3.42;
float ren = (float) 4.21;
float jak = duk/ren;
To jest tzw. casting: http://ggoralski.pl/?p=1512
„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??