אובייקטים ו-OOP

מהו אובייקט?

אובייקט (object) הוא מופע של מחלקה. המחלקה היא התבנית, האובייקט הוא "דבר" קונקרטי שנוצר לפי התבנית.

אנלוגיה: מחלקה = תוכנית אדריכלית של בית. אובייקט = הבית שבנו בפועל. תוכנית אחת - הרבה בתים.

תכנות מונחה עצמים (OOP)

Object-Oriented Programming הוא גישה לתכנות שבה מארגנים את הקוד סביב "אובייקטים" - ישויות עם: - מצב (state) - נתונים שהם שומרים - התנהגות (behavior) - פעולות שאפשר לעשות עליהם

Java היא שפה שבעצם המהות שלה היא מונחית עצמים - הכל סובב סביב מחלקות ואובייקטים.

דוגמה פשוטה

public class Person {
    // שדות (מצב)
    String name;
    int age;

    // מתודות (התנהגות)
    public void greet() {
        System.out.println("שלום, אני " + name);
    }
}

יצירה ושימוש

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        p.name = "דוד";
        p.age = 30;

        p.greet();   // "שלום, אני דוד"
    }
}

בנאי (Constructor)

בנאי הוא מתודה מיוחדת שרצה ברגע יצירת האובייקט. שמה זהה לשם המחלקה, ואין לה טיפוס חזרה.

public class Person {
    String name;
    int age;

    // בנאי
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void greet() {
        System.out.println("שלום, אני " + name);
    }
}

שימוש

Person p1 = new Person("דוד", 30);
Person p2 = new Person("רחל", 25);

p1.greet();
p2.greet();

this

this היא הפנייה לאובייקט הנוכחי. שימושי כשיש התנגשות שמות בין פרמטר לשדה:

public Person(String name, int age) {
    this.name = name;   // this.name = השדה, name = הפרמטר
    this.age = age;
}

בנאי ברירת מחדל

אם לא מגדירים בנאי - Java יוצרת בנאי ריק בעצמה:

public class Dog {
    String name;
    // אין בנאי מוגדר - Java יוצרת: public Dog() {}
}

Dog d = new Dog();   // עובד

אבל אם מגדירים בנאי - הברירת מחדל נעלמת:

public class Dog {
    String name;

    public Dog(String name) {
        this.name = name;
    }
}

Dog d = new Dog();          // שגיאה!
Dog d2 = new Dog("רקסי");   // עובד

הסתרה (Encapsulation)

עיקרון יסוד ב-OOP: לא לחשוף את המצב הפנימי של אובייקט ישירות. במקום זה - לעבוד דרך מתודות ציבוריות.

שלא כמו שצריך

public class BankAccount {
    public double balance;
}

BankAccount acc = new BankAccount();
acc.balance = -1000;   // בעיה! אפשר להגדיר כל ערך

כמו שצריך

public class BankAccount {
    private double balance;

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }
}

מילות מפתח לנגישות

מילת מפתח משמעות
public נגיש מכל מקום
private נגיש רק מתוך המחלקה
protected נגיש למחלקה, לתת-מחלקות, ולאותה חבילה
(ללא) נגיש לאותה חבילה (package-private)

Getters ו-Setters

דפוס סטנדרטי לחשיפה בטוחה של שדות:

public class Person {
    private String name;
    private int age;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }
    public void setAge(int age) {
        if (age >= 0) {
            this.age = age;
        }
    }
}

ארבעת עקרונות ה-OOP

1. Encapsulation - הסתרה

הסתרת הפרטים הפנימיים, חשיפה רק של מה שצריך.

2. Inheritance - ירושה

מחלקה יכולה "לרשת" ממחלקה אחרת, ולהרחיב אותה:

public class Animal {
    String name;
    public void eat() { System.out.println("אוכל..."); }
}

public class Dog extends Animal {
    public void bark() { System.out.println("הב הב!"); }
}

Dog d = new Dog();
d.eat();    // יורש מ-Animal
d.bark();   // משלו

3. Polymorphism - פולימורפיזם

אותה פעולה יכולה להתנהג שונה באובייקטים שונים.

public class Animal {
    public void sound() { System.out.println("רעש כללי"); }
}

public class Dog extends Animal {
    @Override
    public void sound() { System.out.println("הב הב!"); }
}

public class Cat extends Animal {
    @Override
    public void sound() { System.out.println("מיאו!"); }
}

Animal a = new Dog();
a.sound();   // "הב הב!" - לא "רעש כללי"!

4. Abstraction - הפשטה

עבודה עם רעיונות מופשטים, לא עם פרטי היישום.

static מול non-static

  • static - שייך למחלקה עצמה. משותף לכל האובייקטים.
  • non-static - שייך לכל אובייקט בנפרד.
public class Counter {
    static int total = 0;     // משותף
    int mine = 0;              // אישי

    public Counter() {
        total++;
        mine++;
    }
}

Counter c1 = new Counter();   // total=1, c1.mine=1
Counter c2 = new Counter();   // total=2, c2.mine=1, c1.mine=1

toString, equals, hashCode

מתודות ש-Java ממליצה לממש במחלקות שלכם:

toString

@Override
public String toString() {
    return "Person{name='" + name + "', age=" + age + "}";
}

שימוש: System.out.println(person) יקרא אוטומטית ל-toString().

equals

להגדיר "שוויון" בין שני אובייקטים:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof Person)) return false;
    Person other = (Person) obj;
    return this.age == other.age && this.name.equals(other.name);
}

דוגמה מלאה

public class Student {
    private String name;
    private int grade;

    public Student(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() { return name; }
    public int getGrade() { return grade; }

    public boolean passed() {
        return grade >= 60;
    }

    @Override
    public String toString() {
        return name + " (" + grade + ")";
    }
}

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("דוד", 85);
        Student s2 = new Student("רחל", 45);

        System.out.println(s1);   // דוד (85)
        System.out.println(s1.passed());   // true
        System.out.println(s2.passed());   // false
    }
}

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה תפקיד הבנאי (constructor)?

    1. להדפיס את האובייקט
    2. להשוות שני אובייקטים
    3. לאתחל אובייקט חדש ברגע היצירה
    4. למחוק אובייקט
    הצגת התשובה

    תשובה ג. הבנאי רץ עם new וממלא את השדות ההתחלתיים.

  2. למה מגדירים שדות כ-private עם getters ו-setters?

    1. כי public לא קיים
    2. כדי שהקוד יהיה ארוך יותר
    3. כדי שהקוד ירוץ מהר יותר
    4. הכמסה: המחלקה שולטת בגישה לנתונים ויכולה לבדוק ערכים
    הצגת התשובה

    תשובה ד. הכמסה מונעת שינוי לא חוקי מבחוץ, למשל גיל שלילי.

  3. מה מחזירה this בתוך מתודה?

    1. את null
    2. את האובייקט הנוכחי
    3. את המחלקה
    4. את המתודה
    הצגת התשובה

    תשובה ב. this מפנה לאובייקט שעליו המתודה הופעלה.