1. Tworzenie obiektu
No i dotarliśmy do tworzenia obiektów. Już się z tym spotkałeś wcześniej, ale teraz rozkminimy temat bardziej szczegółowo. Tak naprawdę tworzenie obiektów jest mega proste.
Żeby stworzyć obiekt, używasz operatora new. Zazwyczaj tworzysz nową instancję (obiekt) klasy i od razu zapisujesz ją do zmiennej tego samego typu.
Klasa nazwa = new Klasa(parametry);
Gdzie Klasa — typ obiektu, nazwa — nazwa zmiennej (często z małej litery, np. cat), a po prawej od = — tworzenie nowego obiektu tej klasy.
Przykłady:
| Kod | Notatka |
|---|---|
|
Tworzenie obiektu typu object |
|
Tworzenie obiektu typu Cat |
|
Tworzenie obiektu StreamReader z parametrem |
Bardzo często programiści nazywają zmienne tak samo jak klasy, tylko z małej litery. Dla początkującego taki kod może być mylący:
| Kod |
|---|
|
|
|
W rzeczywistości w tym kodzie nie ma nic strasznego — to zupełnie normalny kod, gdzie tworzysz zmienną i od razu inicjalizujesz ją obiektem tego samego typu.
Po lewej — deklaracja zmiennej, po prawej — tworzenie nowego obiektu w pamięci za pomocą new. I tyle!
2. Konstruktor
Pewnie często widziałeś, że przy tworzeniu obiektu przekazuje się jakieś parametry. Do niektórych obiektów przekazujesz parametry, do innych nie. Jak w ogóle działa ten mechanizm z parametrami?
Tu też jest prosto: każda klasa ma specjalną metodę (albo metody), które ogarniają parametry przy tworzeniu obiektu. Takie metody nazywają się konstruktory. A jedna metoda to po prostu konstruktor.
Rozpoznać metodę-konstruktor w kodzie jest łatwo. Taka metoda ma dwie cechy:
- nazwa metody-konstruktora jest taka sama jak nazwa klasy (i zaczyna się z dużej litery)
- konstruktor nie ma typu zwracanego (nawet void się nie pisze).
Ogólny wygląd jest taki:
modyfikatory Klasa(parametry)
{
kod konstruktora
}
Przykład deklaracji konstruktora:
public class Point
{
public int X;
public int Y;
public Point(int x, int y) // Konstruktor
{
X = x;
Y = y;
}
}
Użycie:
Point p = new Point(5, 10); // Wywołanie konstruktora
Przy tworzeniu obiektu przez new Point(5, 10) zostanie wywołany konstruktor z dwoma parametrami, które zainicjalizują pola X i Y.
Czasem parametry konstruktora mają takie same nazwy jak pola — dla wygody. Taki konflikt nazw rozwiązuje się przez słowo kluczowe this:
public Point(int x, int y)
{
this.x = x; // this.x — pole obiektu, x — parametr konstruktora
this.y = y;
}
3. Wywołanie konstruktora
Kiedy piszesz new Klasa(parametry), to C#:
- tworzy nowy obiekt w pamięci,
- wywołuje odpowiedni konstruktor, przekazując twoje parametry.
Przykład z klasą kota:
public class Cat
{
public string Name;
public int Age;
public Cat(string name, int age)
{
Name = name;
Age = age;
}
}
Użycie:
Cat cat = new Cat("Basil", 2); // Można: wywoła się konstruktor z dwoma parametrami
Cat cat2 = new Cat("Basil"); // Nie można: nie ma takiego konstruktora — błąd kompilacji
Cat cat3 = new Cat(); // Nie można: brak konstruktora bez parametrów — błąd kompilacji
Jeśli klasa ma tylko konstruktor z parametrami, musisz przy tworzeniu obiektu przekazać dla nich wartości.
4. Kilka konstruktorów
Ale jeśli chcesz, możesz dodać do klasy kilka konstruktorów. Nie ma żadnych ograniczeń co do liczby konstruktorów czy ich parametrów. Przy tworzeniu obiektu kompilator sam wybierze odpowiedni konstruktor na podstawie parametrów.
Przykład:
public class Cat
{
public const int NIEZNANY = -1;
public string Name;
public int Age;
public Cat(string name, int age)
{
Name = name;
Age = age;
}
public Cat(string name)
{
Name = name;
Age = NIEZNANY; // Wartość "domyślna" dla nieznanego wieku
}
}
Użycie:
Cat cat1 = new Cat("Basil", 2); // Używa pierwszego konstruktora
Cat cat2 = new Cat("Purria"); // Używa drugiego konstruktora
Cat cat3 = new Cat(); // Błąd! Brak konstruktora bez parametrów
Założyliśmy, że wiek kota może być nieznany. Na taką sytuację dodaliśmy w kodzie specjalną stałą — NIEZNANY i konstruktor, który przyjmuje tylko jeden parametr — imię kota.
Zwróć uwagę, że wciąż inicjalizujemy obie zmienne klasy w obu konstruktorach. Nieznane/brakujące parametry zastępujemy stałą NIEZNANY.
5. Konstruktor domyślny
Jeśli twoja klasa nie ma żadnego konstruktora, kompilator automatycznie doda pusty konstruktor bez parametrów:
public ClassName()
{
}
Ale jeśli w klasie zadeklarujesz choć jeden własny konstruktor — automatycznie pusty konstruktor już nie zostanie dodany.
Przykład 1:
public class Cat
{
public string Name;
public int Age;
}
// Można:
Cat cat = new Cat(); // Zostanie wywołany konstruktor domyślny (bez parametrów)
Przykład 2:
public class Cat
{
public string Name;
public int Age;
public Cat(string name) { Name = name; }
}
// Nie można:
Cat cat = new Cat(); // Błąd: nie ma już konstruktora bez parametrów!
6. Inicjalizacja zmiennych
W C# zmienne klasy możesz inicjalizować albo od razu przy deklaracji, albo w konstruktorze.
Przykład:
public class Cat
{
public string Name;
public int Age = -1; // Wartość początkowa
public Cat(string name, int age)
{
Name = name;
Age = age; // Nadpisuje wartość początkową
}
public Cat()
{
Name = "Bezimienny";
// Age zostaje -1 (wartość początkowa)
}
}
Wyjaśnienie:
- Przy tworzeniu przez new Cat("Basil", 2) zmienna Age najpierw będzie -1, ale potem konstruktor przypisze jej 2.
- Przy tworzeniu przez new Cat() — Age zostanie -1.
7. Kolejność inicjalizacji zmiennych
Dane nowego obiektu są inicjalizowane w takiej kolejności:
- Pola klasy najpierw dostają wartości domyślne (0 dla int, null dla typów referencyjnych itd.).
- Potem wykonują się inicjalizatory, które podałeś przy deklaracji pól, w kolejności ich występowania w kodzie.
- I dopiero potem wykonuje się kod konstruktora.
Zmienne są inicjalizowane przed konstruktorem i w kolejności deklaracji. Dlatego uważaj na zależności między polami.
Zły przykład
Niestatycznych pól nie można inicjalizować innymi niestatycznymi zmiennymi:
public class Solution
{
public int a = 1;
public int b = a; // nie można użyć a
public int c = a + b; // nie można użyć a i b
}
// Taki kod wywoła błąd kompilacji!
Dobry przykład
Dla statycznych zmiennych wszystko będzie działać:
public class Solution
{
public static int a = 1; // Jawnie ustawiamy a = 1
public static int b = a + 2; // b = 1 + 2 ⇒ 3
public static int c = a + b + 3; // c = 1 + 3 + 3 ⇒ 7
public Solution()
{
Console.WriteLine($"a = {a}, b = {b}, c = {c}");
// Wypisze: a = 1, b = 3, c = 7 — dokładnie to, czego się spodziewasz
}
}
Dobry przykład 2
Dla statycznych pól możesz nawet napisać tak:
public class Solution
{
public static int a = b + c + 1; // b i c jeszcze równe 0
public static int b = a + c + 2; // a == 1, c jeszcze równe 0
public static int c = a + b + 3; // a == 1, b == 3
}
GO TO FULL VERSION