Datové typy v Javě

Tomáš Pitner, upravil Marek Šabo
tomp@fi.muni.cz

Úvod k datovým typům v Javě

  • Existují dvě základní kategorie datových typů: primitivní a objektové
Primitivní
  • v proměnné je uložena přímo hodnota
  • např. int, long, double, boolean, …​
Objektové
  • musí se nejdřív zkonstruovat (použitím new)
  • do proměnné se uloží pouze odkaz
  • např. String, Person, …​

Datové typy primitivní

integrální typy

zahrnují typy celočíselné (byte , short , int a long) a typ char

čísel s pohyblivou řádovou čárkou

float a double

logických hodnot

boolean

Výchozí (default) hodnoty

  • Každý typ má svou výchozí (default) hodnotu, na kterou je nastaven, není-li hned přiřazena jiná.
  • Dle Java Language Specification: Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10):

    • For type byte, the default value is zero, that is, the value of (byte)0.
    • For type short, the default value is zero, that is, the value of (short)0.
    • For type int, the default value is zero, that is, 0.
    • For type long, the default value is zero, that is, 0L.
    • For type float, the default value is positive zero, that is, 0.0f.
    • For type double, the default value is positive zero, that is, 0.0d.
    • For type char, the default value is the null character, that is, '\u0000'.
    • For type boolean, the default value is false.
    • For all reference types (§4.3), the default value is null

Na co se vztahují výchozí hodnoty

  • Automatické nastavení proměnných na výchozí hodnoty se tedy vztahuje na proměnné objektů a tříd (atributy) a prvky polí.
  • Nevztahuje se na lokální proměnné a parametry, ty musejí být před prvním použitím nastaveny, inicializovány.

Příklad výchozí hodnoty

int i; // automatically i = 0
Více informací najdete na: The Java Tutorials: Primitive Data Types.

Zajímavosti a odlišnosti

  • V Javě neexistuje možnost typy rozsahově či interpretačně modifikovat (žádné unsigned int apod.)
  • Pro velká čísla lze v nových verzích Javy použít notaci s podtržítkem k oddělení řádů po tisících:
private int bigNumber = 123_456_789;

Datové typy objektové

  • objektovými typy v Javě jsou všechna ostatní typy
  • třídy
  • rozhraní ("téměř totéž, co třídy")
  • pole (ano, v Javě jsou samotná pole objekty)

Výchozí hodnota objektového typu je null — tzv. "ukazatel na nic".

Příklad použití objektového typu

Person p; // p is null automatically
p = new Person(); // now p references to an object
  • Objektový typ je všechno, kde se používá operátor new.

Shrnutí

Základní rozdíl je v práci s proměnnými.

primitivní typy

přímo obsahují danou hodnotu

objektové typy

obsahují pouze odkaz na příslušný objekt

  • Důsledek: dvě objektové proměnné mohou nést odkaz na tentýž objekt

Přiřazení primitivní proměnné

  • Hodnota proměnné se nakopíruje:
double a = 1.23456;
double b = a;
a += 2;
// a is 3.23456
// b is 1.23456

Přiřazení objektové proměnné

  • Objektové proměnné ukazují na stejný objekt:
public class Counter {
   private double value;
   public Counter(double v) {
      value = v;
   }
   public void add(double v) {
      value += v;
   }
}
...
Counter c1 = new Counter(1.23456);
Counter c2 = c1;
c1.add(2);
// c1 has value 3.23456
// c2 has value 3.23456

Operátor ==

  • Pro primitivní typy porovnává hodnoty:
1 == 1 // true
1 == 2 // false
  • Pro objektové typy porovnává odkazy:
Counter c1 = new Counter(1.23456);
Counter c2 = c1;
c1 == c2 // true
c1 == new Counter(1.23456) // false
  • Na porovnání hodnot objektových typů se používá equals, probereme později.

Pole v zkratce

  • Vytvoření, naplnění a získání hodnot vypadá následovně:
int[] array = new int[2];
array[0] = 1;
array[1] = 4;
System.out.println("First element is: " + array[0]);
  • Deklarace: typ[] jméno = new typ [velikost];
  • typ může být i objektový: Person[] p = new Person[3];

Velikost pole

  • velikost pole je daná při jejím vytvoření a nelze ji měnit
  • V budoucnu budeme probírat kolekce (seznam, slovník), což je mocnější složený datový typ než pole
  • jejich počty prvků se mohou dynamicky měnit

Mělká kopie

  • Přiřazení proměnné objektového typu (což je i pole) vede pouze k duplikaci odkazu, nikoli celého odkazovaného objektu.
  • Modifikace jedné proměnné se pak projeví u i té druhé.
int[] array = new int[] {1, 4, 7};
int[] array2 = array;
array[1] = 100;
System.out.println(array[1]); // prints 100
System.out.println(array2[1]); // prints 100
  • Takovému kopírování se říká mělká kopie (shallow copy).

Hluboká kopie

Provedeme-li vytvoření nového pole, pak array2 obsahuje kopii (duplikát) původního pole.

int[] array = new int[] {1, 4, 7};
int[] array2 = Arrays.copyOf(array, array.length);
array[1] = 100;
System.out.println(array[1]); // prints 100
System.out.println(array2[1]); // prints 4
  • Takovému kopírování se říká hluboká kopie (deep copy).

Metoda copyOf bere dva parametry — původní pole a počet prvků, kolik se má nakopírovat.

Hluboká kopie u objektů I

  • Obdobně to funguje i objektů.
Person[] people = new Person[] { new Person("Jan"), new Person("Adam")};
Person[] people2 = Arrays.copyOf(people, people.length);
people[1] = new Person("Pepa");
System.out.println(people[1].getName()); // prints Pepa
System.out.println(people2[1].getName()); // prints Adam
  • Co kdybychom změnili jenom jméno (atribut objektu)?

Hluboká kopie u objektů II

  • Do cílového pole se zduplikují jenom odkazy na objekty Person, nevytvoří se kopie objektů Person!
Person[] people = new Person[] { new Person("Jan"), new Person("Adam")};
Person[] people2 = Arrays.copyOf(people, people.length);
people[1].setName("Pepa"); // changes Adam to Pepa
System.out.println(people[1].getName()); // prints Pepa
System.out.println(people2[1].getName()); // prints Pepa
  • Jinými slovy, pole mají sice různý odkaz (šipku), ale na stejný objekt.
  • V předešlém příkladu jsme změnili odkaz na jiný objekt.
  • Teď jsme změnili obsah objektu, na který ukazují oba odkazy.

/