Rozdział 6 - Tablice - Porównywanie tablic i zmiana rozmiaru tablic

Prędzej czy później będziemy w naszych programach potrzebowali porównać ze sobą dwie tablice, by odpowiedzieć na pytanie, czy zawierają takie same elementy. Spróbujmy porównać dwie tablice za pomocą operatora ==:

Nazwa pliku: PorownywanieTablicOperatorRownosci.java
public class PorownywanieTablicOperatorRownosci {
  public static void main(String[] args) {
    int[] pierwszaTablica = { 10, 5, 20 };
    int[] drugaTablica = { 10, 5, 20 };

    if (pierwszaTablica == drugaTablica) {
      System.out.println("Tablice sa takie same.");
    } else {
      System.out.println("Tablice nie sa takie same.");
    }
  }
}

Ku potencjalnemu zdziwieniu, na ekranie zobaczymy komunikat:

Tablice nie sa takie same.

Tablice te mają co prawda takie same elementy, lecz każda z nich jest osobnym obiektem. Tablice to typy referencyjne (złożone), podobnie jak typ String, a w przeciwieństwie do ośmiu poznanych już typów podstawowych (int, boolean, double itd.). O typach referencyjnych będziemy bardzo dużo mówić zaczynając od rozdziału o klasach. Na razie zapamiętajmy, że nie powinniśmy porównywać tablic za pomocą operatora == bądź !=.

W przypadku typu String, wartości należy porównywać za pomocą metody equals, jednakże porównywanie dwóch tablic musimy wykonać w inny sposób. Aby sprawdzić, czy dwie tablice mają takie same wartości (i w takiej samej kolejności), musimy skorzystać z pętli i przejść przez wszystkie elementy tablic i porównać je ze sobą:

Nazwa pliku: PorownajTablice.java
public class PorownajTablice {
  public static void main(String[] args) {
    int[] pierwszaTablica = { 10, 5, 20 };
    int[] drugaTablica = { 10, 5, 20 };

    // jezeli tablice maja rozne rozmiary,
    // to na pewno nie bede takie same
    if (pierwszaTablica.length != drugaTablica.length) {
      System.out.println("Tablice nie sa takie same.");
    } else {
      boolean czyRoznicaZnaleziona = false;

      for (int i = 0; i < pierwszaTablica.length; i++) {
        // sprawdzamy, czy elementy o tych samych indeksach roznia
        // sie wartoscia - jezeli znajdziemy choc jedna roznice,
        // to bedziemy wiedziec, iz tablice nie sa takie same
        if (pierwszaTablica[i] != drugaTablica[i]) {
          czyRoznicaZnaleziona = true;
          break;
        }
      }

      if (czyRoznicaZnaleziona) {
        System.out.println("Tablice nie sa takie same.");
      } else {
        System.out.println("Tablice sa takie same.");
      }
    }
  }
}

Jak widać, jest dużo więcej zachodu z porównywaniem dwóch tablicy, niż można się było spodziewać.

Najpierw sprawdzamy rozmiar obu tablic – jeżeli tablice mają różną liczbę elementów, to na pewno nie będą takie same. Jeżeli rozmiar się zgadza, w pętli przechodzimy przez wszystkie elementy tablic i porównujemy elementy o tych samych indeksach – jeżeli znajdziemy chociaż jedną parę elementów, które się różnią, będzie to oznaczało, że tablice nie są takie same – możemy w takim przypadku skorzystać z instrukcja break, by zakończyć pętlę. Na końcu programu, na podstawie wartości zmiennej czyRoznicaZnaleziona, wypisujemy informację, czy tablice są takie same, czy nie. Na ekranie w tym przypadku zobaczymy:

Tablice sa takie same.

W rozdziale o klasach dowiemy się dokładnie o różnicach pomiędzy typami referencyjnymi (złożonymi), a ośmioma typami podstawowymi (int, boolean, char itd.). Na razie zapamiętajmy, że aby porównać zawartość dwóch tablic, musimy skorzystać z pętli i porównać ze sobą elementy obu tablic na odpowiednich indeksach.

Dla dociekliwych

Zmienne typu referencyjnego wskazują na obiekty w pamięci – nie są konkretnie tymi obiektami, które zostały utworzone – w przykładzie powyżej, zmienna pierwszaTablica to nie tablica trzech elementów, lecz wskazanie na obiekt w pamięci, który jest tablicą trzech elementów typu int. Podobnie ze zmienną drugaTablica. Obie zmienne wskazują na dwa różne obiekty w pamięci – dlatego próba ich porównania za pomocą operatora == zwraca false, ponieważ obie tablice są różnymi obiektami w pamięci, tzn. nie są tym samym obiektem. W rozdziale o klasach dowiemy się dużo więcej o typach referencyjnych (złożonych), ich cechach, sposobie użycia, oraz tworzenia.

Zmiana rozmiaru tablicy

Wiemy już, że możemy utworzyć tablicę za pomocą słowa kluczowego new – albo podając, ile elementów tablica będzie mogła przechowywać, albo, bez podawania rozmiaru tablicy, podać elementy, z których tablica ma się składać:

int[] calkowite = new int[10];

double[] rzeczywiste;
rzeczywiste = new double[] { 3.14 , 2.44, 0.99 };

Wiemy już także, że tablice mają określony w trakcie ich tworzenia rozmiar, który możemy sprawdzić używając atrybutu length.

Czasem może się zdarzyć, że będziemy potrzebowali zwiększyć rozmiar tablicy, jednakże rozmiaru raz utworzonej tablicy w trakcie działanie programu zmienić się nie da. Jest jednak możliwe rozwiązanie: możemy utworzyć nową tablicę o większym rozmiarze i przepisać do niej elementy z poprzedniej tablicy, a następnie przypisać nową tablicę do zmiennej, która poprzednio wskazywała na tablicę z mniejszą liczbą elementów:

Nazwa pliku: NowaTablicaZWiekszaLiczbaElementow.java
public class NowaTablicaZWiekszaLiczbaElementow{
  public static void main(String[] args) {
    int[] liczby = { 10, 100, -5 };

    System.out.println("Elementy tablicy liczby:");

    for (int x : liczby) {
      System.out.print(x + ", ");
    }

    System.out.println(); // przejdz do nowej linii

    // tworzymy druga tablice o wiekszym rozmiarze
    int[] tymczasowaTabela = new int[5];

    // przepisujemy elementy z pierwszej tablicy
    for (int i = 0; i < liczby.length; i++) {
      tymczasowaTabela[i] = liczby[i];
    }

    // ustawiamy dodatkowe elementy
    tymczasowaTabela[3] = 20;
    tymczasowaTabela[4] = 1;

    // przypisujemy druga tablice do pierwszej
    liczby = tymczasowaTabela;

    System.out.println("Elementy tablicy liczby:");

    for (int x : liczby) {
      System.out.print(x + ", ");
    }
  }
}

W tym programie utworzyliśmy tablicę o trzech elementach, dostępną za pomocą zmiennej o nazwie liczby, i wypisaliśmy jej zawartość na ekran.

Następnie, dla przykładu, w powyższym programie symulujemy potrzebę posiadania tablicy o większej liczbie elementów – tworzymy więc nową tablicę tymczasowaTablica, która może przechowywać 5 elementów. Następnie, w pętli przepisujemy wartości z mniejszej tablicy do większej.

Po wykonaniu pętli, ustawiamy dwa ostatnie elementy nowej tablicy przykładowymi wartościami. W końcu, w podświetlonej linii kodu, ustawiamy zmienną liczby, by wskazywała na nowo utworzoną tablicę. Na końcu programu ponownie wypisujemy elementy tej tablicy – tym razem widzimy pięć liczb:

Elementy tablicy liczby: 10, 100, -5, Elementy tablicy liczby: 10, 100, -5, 20, 1,

W ten sposób, tablica liczby może teraz przechowywać pięć elementów, chociaż na początku programu mogła przechowywać tylko trzy elementy – a przynajmniej tak by się mogło wydawać. Oryginalna tablica trój-elementowa się nie zmieniła – to, co osiągnęliśmy w tym programie, to utworzenie nowej tablicy o większej liczbie elementów, oraz ustawiliśmy zmienną liczby, by na nią wskazywała. Wynika to z faktu, że tablice są przykładem typów referencyjnych (złożonych), o których dokładnie sobie opowiemy w rozdziale o klasach.

Dla dociekliwych

W poprzednim podrozdziale dowiedzieliśmy się, że porównywać tablice powinniśmy poprzez sprawdzenie ich rozmiarów i elementów, a nie operatora ==. Jednakże, gdybyśmy teraz porównali tablice liczby oraz tymczasowaTabela za pomocą operatora ==, to zwróciłby on wartość true! Powodem jest to, że obie zmienne wskazują teraz na ten sam obiekt w pamięci. W rozdziale o klasach wyjaśnimy sobie dokładnie to zachowanie.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Nie musisz podawać swojego imienia, e-mailu, ani strony www, aby opublikować komentarz. Komentarze muszą zostać zatwierdzone, aby były widoczne na stronie.