« poprzedni punkt 

5. Konwersje arytmetyczne

Ogólnie, jeżeli zmienna jest typu A to nie można jej przypisać wartości typu B. Np. taki zapis w programie spowoduje błąd w kompilacji:

int a = "Ala ma kota";

gdyż a jest zmienną typu int, a wyrażenie "Ala ma kota" jest literałem łańcuchowym i  jest typu  String.

Byłoby jednak nierozumnie stosować tę zasadę w całej rozciągłości wobec typów arytmetycznych. Przecież to są liczby i często chcielibyśmy jakąś wartość liczbową przypisać zmiennej typu arytmetycznego nie bacząc na typy.

Zmiana typu wyrażenia nazywa się konwersją lub - inaczej - rzutowaniem (ang. cast)

Te konwersje arytmetyczne, które nie mogą doprowadzić do utraty informacji reprezentowanej przez wartość wyrażenia dokonywane są w sposób niejawny, niejako automatyczny.
Możemy np. bez przeszkód przypisać zmiennej typu double wartość zmiennej typu int:

int a = 10;
double d = a;

bowiem każda wartość zmiennej typu int "zmieści się" w zmiennej typu double.

Takie konwersje nazywają się rozszerzającymi, bo przekształcane są "węższe" typu do "szerszych" (mogących reprezentować większe spektrum wartości).

Gdybyśmy jednak chcieli wykonać operację odwrotną:

double d = 10.1;
...
int a = d;

to kompilator będzie sygnalizował błąd. Taki zapis jest niedopuszczalny, ponieważ przy  okazji takiego przypisania możemy stracić informację zawartą w zmiennej "szerszego" typu.
Konwersja w tym przypadku nazywa się konwersją zawężającą i możliwa jest do wykonania tylko pod warunkiem użycia operatora konwersji. Mówimy, że konwersje zawężające muszą być wykonywane jawnie, za pomocą operatora konwersji. Użycie operatora konwersji oznacza, że programista świadomie decyduje się na przekształcenie typów, przy którym może nastąpić strata informacji. Że nie jest to przypadkowy błąd w programie.

Operator konwersji (rzutowania) ma postać:

        (nazwa_typu) wyrażenie

gdzie nazwa_typu - typ do jakiego przekształcany jest aktualny typ wyrażenia

W poprzednim przykładzie powinniśmy więc napisać:

double d = 10.9;
...
int a = (int) d;

i teraz kompilator pozwoli nam na pozostawienie takiego zapisu w programie.

Warto zwrócić uwagę, że przy tej okazji może faktycznie nastąpić utrata informacji. W naszym przykładzie zmienna a będzie miała wartość 10 - straciliśmy całą część ułamkową liczby. Podkreślmy: to nie jest zaokrąglenie, część ulamkowa jest po prostu odrzucana. Oczywiście nie zawsze informacja będzie tracona (gdy d = 10.0, to a = 10 i mamy praktycznie to samo).

Bardzo często przy operowaniu na znakach (typo char) i ich kodach liczbowych potrzebne jest wykonywanie konwersji.
Obrazuje to poniższy program:

public class Char {

  public static void main(String[] args) {

     char c = 'a';
     int kod = c;
     System.out.println("Kod znaku " + c + " = " + kod);
     kod = 77;
     c = (char) kod;
     System.out.println("Kod znaku " + c + " = " + kod);

     // Czasem trzeba użyć jawnej konwersji rozszerzającej
     System.out.println("Kod znaku " + '*' + " = " + (int) '*');

     // Oczywiście - zawężające zawsze trzeba podawać jawnie
     System.out.println("Kod znaku " + (char) 66 + " = " + 66);

  }

}

Kod znaku a = 97
Kod znaku M = 77
Kod znaku * = 42
Kod znaku B = 66

który wyprowadzi na konsolę następującą informację:

W trakcie wyliczania wartości wyrażeń arytmetycznych dokonywane są automatyczne konwersje nazywane promocjami numerycznymi.

Promocja numeryczna polega na przekształceniu typów argumentów operatorów arytmetycznych do typu wspólnego dla ich argumentów

Odpowiedź na pytanie jaki jest ten wspólny typ daje następująca reguła.


Promocje argumentów operatorów dwuargumentowych są wykonywane w następujący sposób:
  • jeżeli jeden z argumentów jest typu double, drugi przekształcany jest do typu double,
  • w przeciwnym razie, jeżeli jeden z argumentów jest typu float, drugi przekształcany jest do typu float,
  • w przeciwnym razie, jeżeli jeden z argumentów jest typu long, drugi przekształcany jest do typu long,
  • w przeciwnym razie oba argumenty przekształcane są do typu int.
 


« poprzedni punkt