Dlaczego to pytanie wraca na prawie każdej rekrutacji
Zanim rekruter zacznie Cię przepytywać z SOLID, wzorców projektowych czy dependency injection, prawie zawsze padnie jedno banalne pytanie: „Jaka jest różnica między klasą a obiektem?”. Brzmi jak coś, co powinieneś ogarnąć w pierwszym tygodniu nauki C# — i teoretycznie tak jest. Problem w tym, że pod presją rozmowy potrafi się to mocno rozjechać.
To jest pytanie raczej z tych podstawowych. Pytani są o to juniorzy, natomiast warto znać odpowiedź, ponieważ nawet jako mid możesz być zaskoczony tym pytaniem.
Wbrew pozorom rekruterzy nie pytają o to, żeby Cię złapać. Pytają, bo to szybki test, czy rozumiesz fundament — a jeśli mylisz klasę z obiektem, to o DI, wzorcach projektowych i architekturze nie ma co rozmawiać. W tym wpisie rozbieram całą mechanikę na czynniki pierwsze i pokazuję, jak na rekrutacji powiedzieć to jednym zdaniem, a potem rozwinąć tak, żeby prowadzący od razu wiedział, że wiesz, o czym mówisz.
Klasa — szablon, nie byt
Najprostsza analogia, która zawsze działa: klasa to przepis w książce kucharskiej. To, że masz przepis na pizzę, nie oznacza, że masz pizzę. Przepis tylko opisuje, jak ma wyglądać pizza, jakie ma mieć składniki i co się z nimi robi. Dopiero na podstawie przepisu możesz upiec konkretną pizzę.
W kodzie wygląda to tak:
// Klasa — szablon
public class Dog
{
public string Name { get; set; }
public int Age { get; set; }
}
To jest klasa Dog. Nie ma tu żadnego konkretnego psa. Nie ma Rexa, nie ma Burka — jest tylko opis: „każdy pies ma imię i wiek”. Klasa definiuje:
- pola i właściwości — czyli jakie dane obiekt będzie przechowywał (
Name,Age) - metody — co obiekt będzie potrafił zrobić (np.
Bark()) - konstruktor — jak obiekt jest tworzony i co jest wymagane do jego powstania
- modyfikatory dostępu (
public,private,protected) — co jest widoczne z zewnątrz, a co jest schowane wewnątrz
Jeśli konstruktor wymaga parametrów, to bez ich podania nie utworzysz żadnego obiektu — kompilator Cię w tym miejscu zatrzyma. To taki kontrakt: „chcesz instancję? to mi powiedz, jakiego rocznika i jakiej marki ma być”.
Dopóki siedzisz w pliku .cs i patrzysz na class Dog { ... } — pracujesz na szablonie. Szablon sam w sobie nic nie robi, niczego nie przechowuje, niczego nie modyfikuje. Jest tylko instrukcją.
Obiekt — instancja, która żyje w pamięci
Dopiero wtedy, kiedy piszesz słowo kluczowe new, dzieje się magia — powstaje obiekt. Obiekt to konkretny egzemplarz klasy, który istnieje w pamięci aplikacji i ma swój własny stan.
// Obiekt — instancja
var rex = new Dog { Name = "Rex", Age = 5 };
var burek = new Dog { Name = "Burek", Age = 3 };
// Dwa różne obiekty tej samej klasy
Console.WriteLine(rex.Name); // Rex
Console.WriteLine(burek.Name); // Burek
Tutaj mamy już dwa psy. Oba są zbudowane według tego samego „przepisu” (klasy Dog), ale każdy żyje własnym życiem. Rex ma swoją sekcję w pamięci, Burek ma swoją. Zmienisz wiek Rexa — Burek się tym nie interesuje, bo siedzi gdzie indziej w pamięci.
Te dwa obiekty są od siebie niezależne. To są dwa osobne miejsca w pamięci aplikacji. Na jednym coś robię, drugi sobie siedzi na boku i w ogóle się tym nie interesuje.
I tu dochodzimy do rzeczy, która najczęściej wysadza kandydatów — referencje.
Referencje — dlaczego kopia obiektu to często ten sam obiekt
Zmienna rex nie przechowuje całego psa. Przechowuje adres w pamięci, pod którym ten pies siedzi. Dlatego klasy w C# to tzw. typy referencyjne. Efekt jest taki, że kiedy spróbujesz zrobić „kopię” w najprostszy sposób:
var rexCopy = rex;
rexCopy.Age = 99;
Console.WriteLine(rex.Age); // 99 (!)
Console.WriteLine(rexCopy.Age); // 99
To zmienna rexCopy dostaje ten sam adres co rex. Obie zmienne wskazują na to samo miejsce w pamięci. Zmodyfikujesz jedną — zmienia się druga, bo to fizycznie ten sam obiekt. To nie jest błąd — to jak działają typy referencyjne w .NET.
Jeśli chcesz prawdziwej kopii, musisz jawnie utworzyć nowy obiekt (np. przez konstruktor kopiujący, record with { ... } w nowszym C#, albo serializację). Sam operator przypisania kopiuje tylko referencję, a nie zawartość.
Ten moment na rekrutacji rozróżnia juniorów, którzy „umieją OOP z prezentacji”, od tych, którzy rzeczywiście pisali kod i widzieli, że zmiana jednej zmiennej zmieniła drugą, i potem debugowali to pół dnia.
Jak odpowiedzieć na rozmowie rekrutacyjnej
Jeśli jutro masz rozmowę i padnie to pytanie, odpowiadaj w trzech warstwach — od najprostszej do technicznej. Prowadzący zobaczy, że rozumiesz temat, a jednocześnie nie gadasz jak podręcznik.
Warstwa 1 — jedno zdanie:
Klasa to szablon, definicja, typ. Obiekt to konkretna instancja tej klasy, utworzona operatorem
newi żyjąca w pamięci.
Warstwa 2 — analogia:
Klasa to przepis w książce kucharskiej, obiekt to konkretnie upieczone ciasto. Przepis możesz mieć jeden, a ciast na jego podstawie — setki, i każde będzie miało własny stan (np. różną ilość posypki).
Warstwa 3 — techniczny konkret:
- klasa definiuje pola, właściwości, metody i konstruktor
- obiekt powstaje przez
new ClassName(...)— .NET przydziela pamięć na stercie (heap), wywołuje konstruktor i zwraca referencję - zmienna typu klasowego przechowuje adres do obiektu, nie cały obiekt — bo klasy to typy referencyjne
- dwa obiekty tej samej klasy są niezależne w pamięci, ale dwie zmienne mogą wskazywać na ten sam obiekt
Jeśli rekruter Cię podpyta o memory model, sterty vs stos, albo różnicę między class a struct — wiesz już, w którą stronę idzie rozmowa, i masz czas się do tego przygotować osobno. Ale sam fundament „klasa vs obiekt” masz ograny.
Klasa jest takim przepisem, szablonem, definicją. Obiekt to jest konkretna reprezentacja tego przepisu. Obiekty tworzymy przez słowo kluczowe
new.
Dodatkowa rada: nie ucz się tego na pamięć z dokumentacji. Otwórz Ridera albo Visual Studio, stwórz klasę, utwórz dwa obiekty, zmodyfikuj jednemu pole, potem zrób „kopię” i zobacz, co się stanie z referencjami. Pięć minut w debuggerze wchodzi do głowy na lata — a odpowiedź na rekrutacji brzmi wtedy jak Twoja, a nie jak wyrecytowana z książki.
Co dalej?
To jest drugi odcinek z serii Rekrutacja na .NET developera, w której rozbieram pytania padające na realnych rozmowach — od juniorskich fundamentów po rzeczy, które potykają midów. W kolejnych częściach wchodzę głębiej w OOP (dziedziczenie, polimorfizm, interfejsy), DI i async/await.
Jeśli chcesz zobaczyć cały projekt ClassVsObject z filmu, kod jest na moim GitHubie. Do pełnego wideo, na którym pokazuję ten temat krok po kroku w Riderze, podlinkowałem w nagłówku wpisu.
Masz pytanie z rekrutacji, które Cię kiedyś zatrzymało? Napisz w komentarzu pod filmem albo daj znać — jest szansa, że zrobię z tego osobny odcinek.

