مقدمة في Java

ما هي Java؟

Java هي لغة برمجة كائنية التوجه (Object-Oriented Programming) طورتها شركة Sun Microsystems في عام 1995، والآن مملوكة لشركة Oracle.

تاريخ Java:

تم تطوير Java في البداية من قبل جيمس جوسلينج (James Gosling) وفريقه في Sun Microsystems. كان الهدف الأساسي هو إنشاء لغة برمجة يمكن استخدامها في الأجهزة الإلكترونية المختلفة.

مميزات Java:
  • البرمجة الكائنية: تدعم مفاهيم الوراثة والتغليف والتعددية بشكل كامل
  • المنصة المستقلة: "اكتب مرة واحدة، شغل في أي مكان" (Write Once, Run Anywhere) بفضل JVM
  • الذاكرة التلقائية: إدارة تلقائية للذاكرة (Garbage Collection) مما يسهل على المطورين
  • الأمان: بيئة آمنة لتطوير التطبيقات مع حماية من الوصول غير المصرح به
  • قوية ومتعددة الاستخدامات: يمكن استخدامها لتطوير تطبيقات الويب وسطح المكتب والموبايل
مجالات استخدام Java:
  • تطوير تطبيقات الويب (Server-side)
  • تطبيقات Android
  • تطبيقات المؤسسات الكبيرة
  • الأنظمة المالية والمصرفية
  • الألعاب والتطبيقات العلمية
معلومة: Java هي واحدة من أكثر لغات البرمجة شعبية في العالم وتستخدم في ملايين التطبيقات.

بيئة التطوير JDK

ما هو JDK؟

JDK (Java Development Kit) هي مجموعة من الأدوات البرمجية اللازمة لتطوير تطبيقات Java.

مكونات JDK:
  • JRE (Java Runtime Environment): البيئة المطلوبة لتشغيل تطبيقات Java
  • JVM (Java Virtual Machine): الآلة الافتراضية التي تنفذ كود Java
  • Compiler (javac): المترجم الذي يحول كود Java إلى Bytecode
  • Libraries: مكتبات Java القياسية (Java API)
كيفية تثبيت JDK:
  1. قم بتحميل JDK من الموقع الرسمي لـ Oracle
  2. قم بتثبيت JDK على جهازك
  3. قم بتعيين متغيرات البيئة (Environment Variables)
  4. تحقق من التثبيت باستخدام الأمر: java -version
بيئات التطوير المتكاملة (IDEs):
  • IntelliJ IDEA: واحدة من أفضل IDEs لتطوير Java
  • Eclipse: بيئة تطوير شائعة ومجانية
  • NetBeans: بيئة تطوير رسمية من Oracle
  • Visual Studio Code: محرر نصوص خفيف مع إضافات Java

أول برنامج في Java

بنية البرنامج الأساسية:

كل برنامج Java يجب أن يحتوي على كلاس (class) واحد على الأقل يحتوي على دالة main.

مثال برنامج Hello World:
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("مرحباً بكم في Java!");
        System.out.println("هذا أول برنامج لي");
    }
}
شرح الكود:
  • public class HelloWorld: تعريف كلاس باسم HelloWorld. يجب أن يطابق اسم الكلاس اسم الملف
  • public static void main(String[] args): دالة main هي نقطة بداية تنفيذ البرنامج
  • System.out.println(): أمر طباعة النص على الشاشة مع الانتقال لسطر جديد
خطوات التشغيل:
  1. احفظ الملف باسم HelloWorld.java
  2. افتح Terminal/Command Prompt
  3. انتقل إلى مجلد الملف
  4. قم بالتجميع: javac HelloWorld.java
  5. قم بالتشغيل: java HelloWorld
نصيحة: تأكد من كتابة أسماء الكلاسات بأحرف كبيرة في البداية (PascalCase).

المتغيرات وأنواع البيانات الأساسية

ما هي المتغيرات؟

المتغيرات هي أماكن في الذاكرة تستخدم لتخزين البيانات التي يمكن تغييرها أثناء تنفيذ البرنامج.

أنواع البيانات الأساسية (Primitive Types):
النوع الحجم الوصف مثال
byte 1 byte أعداد صحيحة من -128 إلى 127 byte age = 25;
short 2 bytes أعداد صحيحة من -32,768 إلى 32,767 short count = 1000;
int 4 bytes أعداد صحيحة من -2^31 إلى 2^31-1 int number = 100000;
long 8 bytes أعداد صحيحة كبيرة long bigNumber = 1000000L;
float 4 bytes أعداد عشرية (دقة بسيطة) float price = 99.99f;
double 8 bytes أعداد عشرية (دقة عالية) double salary = 5000.50;
char 2 bytes حرف واحد (Unicode) char grade = 'A';
boolean 1 bit true أو false boolean isActive = true;
مثال شامل:
public class Variables {
    public static void main(String[] args) {
        // تعريف المتغيرات
        String name = "أحمد";
        int age = 25;
        double salary = 5000.50;
        boolean isEmployed = true;
        char gender = 'M';
        
        // عرض القيم
        System.out.println("الاسم: " + name);
        System.out.println("العمر: " + age);
        System.out.println("الراتب: " + salary);
        System.out.println("موظف: " + isEmployed);
        System.out.println("الجنس: " + gender);
    }
}
قواعد تسمية المتغيرات:
  • يجب أن تبدأ بحرف أو underscore (_) أو دولار ($)
  • لا يمكن أن تحتوي على مسافات
  • لا يمكن استخدام الكلمات المحجوزة (reserved words)
  • استخدم camelCase للأسماء المركبة: firstName

المعاملات والتعبيرات

أنواع المعاملات في Java:

المعاملات (Operators) هي رموز تستخدم لإجراء عمليات على المتغيرات والقيم.

1. المعاملات الحسابية:
int a = 10, b = 3;
int sum = a + b;      // 13
int diff = a - b;     // 7
int product = a * b;  // 30
int quotient = a / b; // 3
int remainder = a % b; // 1
2. معاملات المقارنة:
int x = 5, y = 10;
boolean isEqual = (x == y);     // false
boolean notEqual = (x != y);    // true
boolean greater = (x > y);      // false
boolean less = (x < y);         // true
boolean greaterEqual = (x >= y); // false
boolean lessEqual = (x <= y);   // true
3. المعاملات المنطقية:
boolean a = true, b = false;
boolean and = a && b;  // false (AND)
boolean or = a || b;   // true (OR)
boolean not = !a;      // false (NOT)
4. معاملات التعيين:
int x = 10;
x += 5;  // x = x + 5  → 15
x -= 3;  // x = x - 3  → 12
x *= 2;  // x = x * 2  → 24
x /= 4;  // x = x / 4  → 6
x %= 4;  // x = x % 4  → 2
5. معاملات الزيادة والنقصان:
int a = 5;
int b = ++a;  // a = 6, b = 6 (Pre-increment)
int c = a++;  // a = 7, c = 6 (Post-increment)
int d = --a;  // a = 6, d = 6 (Pre-decrement)
int e = a--;  // a = 5, e = 6 (Post-decrement)

عبارات الشرط if-else

عبارات الشرط في Java:

تستخدم عبارات الشرط لاتخاذ قرارات في البرنامج بناءً على شروط معينة.

1. if Statement:
int score = 85;

if (score >= 90) {
    System.out.println("ممتاز!");
}
2. if-else Statement:
int age = 18;

if (age >= 18) {
    System.out.println("أنت بالغ");
} else {
    System.out.println("أنت قاصر");
}
3. if-else if-else:
int score = 85;

if (score >= 90) {
    System.out.println("ممتاز!");
} else if (score >= 75) {
    System.out.println("جيد جداً!");
} else if (score >= 60) {
    System.out.println("جيد");
} else {
    System.out.println("راسب");
}
4. Nested if (if متداخل):
int age = 25;
boolean hasLicense = true;

if (age >= 18) {
    if (hasLicense) {
        System.out.println("يمكنك القيادة");
    } else {
        System.out.println("تحتاج رخصة قيادة");
    }
} else {
    System.out.println("أنت قاصر");
}
5. Ternary Operator (معامل شرطي):
int age = 20;
String status = (age >= 18) ? "بالغ" : "قاصر";
System.out.println(status); // بالغ

عبارة switch-case

عبارة switch في Java:

تُستخدم عبارة switch عندما تريد تنفيذ كود مختلف بناءً على قيمة متغيرة.

صيغة switch الأساسية:
int day = 3;

switch (day) {
    case 1:
        System.out.println("الإثنين");
        break;
    case 2:
        System.out.println("الثلاثاء");
        break;
    case 3:
        System.out.println("الأربعاء");
        break;
    case 4:
        System.out.println("الخميس");
        break;
    case 5:
        System.out.println("الجمعة");
        break;
    default:
        System.out.println("يوم آخر");
}
switch مع String (Java 7+):
String language = "Java";

switch (language) {
    case "Java":
        System.out.println("لغة Java");
        break;
    case "Python":
        System.out.println("لغة Python");
        break;
    default:
        System.out.println("لغة أخرى");
}
switch مع Fall-through (بدون break):
int month = 2;

switch (month) {
    case 12:
    case 1:
    case 2:
        System.out.println("الشتاء");
        break;
    case 3:
    case 4:
    case 5:
        System.out.println("الربيع");
        break;
    default:
        System.out.println("فصل آخر");
}
ملاحظة مهمة: لا تنسى استخدام break بعد كل case لتجنب Fall-through غير المقصود.

حلقة for

حلقة for في Java:

تُستخدم حلقة for لتكرار تنفيذ كتلة من الكود لعدد محدد من المرات.

صيغة for الأساسية:
// طباعة الأعداد من 1 إلى 10
for (int i = 1; i <= 10; i++) {
    System.out.println(i);
}
مثال آخر - حساب المجموع:
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;
}
System.out.println("المجموع: " + sum); // 5050
for متداخلة (Nested for):
// طباعة جدول الضرب
for (int i = 1; i <= 10; i++) {
    for (int j = 1; j <= 10; j++) {
        System.out.print(i * j + "\t");
    }
    System.out.println();
}
Enhanced for (for-each):
int[] numbers = {10, 20, 30, 40, 50};

for (int number : numbers) {
    System.out.println(number);
}

حلقة while و do-while

حلقات while و do-while:

تُستخدم عندما لا تعرف عدد مرات التكرار مسبقاً، وتعتمد على شرط.

1. حلقة while:
int count = 1;

while (count <= 5) {
    System.out.println("العدد: " + count);
    count++;
}
2. حلقة do-while:
int num = 1;

do {
    System.out.println(num);
    num++;
} while (num <= 5);
الفرق بين while و do-while:
  • while: يتحقق من الشرط أولاً، قد لا ينفذ الكود أبداً
  • do-while: ينفذ الكود مرة واحدة على الأقل ثم يتحقق من الشرط
مثال عملي - قراءة من المستخدم:
Scanner scanner = new Scanner(System.in);
int number;

do {
    System.out.print("أدخل عدداً موجباً: ");
    number = scanner.nextInt();
} while (number <= 0);

System.out.println("شكراً! العدد: " + number);

المصفوفات Arrays

المصفوفات في Java:

المصفوفة هي بنية بيانات لتخزين مجموعة من العناصر من نفس النوع.

1. إنشاء مصفوفة:
// طريقة 1: إنشاء ثم تعيين
int[] numbers = new int[5];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
numbers[3] = 40;
numbers[4] = 50;

// طريقة 2: إنشاء وتعيين مباشرة
int[] numbers2 = {10, 20, 30, 40, 50};
2. الوصول للعناصر:
int[] arr = {10, 20, 30};
System.out.println(arr[0]); // 10
System.out.println(arr[1]); // 20
System.out.println(arr.length); // 3
3. المرور على المصفوفة:
int[] numbers = {10, 20, 30, 40, 50};

// استخدام for عادية
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

// استخدام for-each
for (int num : numbers) {
    System.out.println(num);
}
4. المصفوفات متعددة الأبعاد:
// مصفوفة ثنائية (2D Array)
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// الوصول للعناصر
System.out.println(matrix[0][0]); // 1
System.out.println(matrix[1][2]); // 6

// المرور على المصفوفة الثنائية
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + " ");
    }
    System.out.println();
}

المصفوفات متعددة الأبعاد

المصفوفات متعددة الأبعاد في Java:

المصفوفات متعددة الأبعاد تسمح بتخزين البيانات في شكل جدول أو مصفوفة من المصفوفات.

1. إنشاء مصفوفة ثنائية:
// طريقة 1: إنشاء ثم تعيين
int[][] matrix = new int[3][3];
matrix[0][0] = 1;
matrix[0][1] = 2;
matrix[0][2] = 3;

// طريقة 2: إنشاء وتعيين مباشرة
int[][] matrix2 = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};
2. المرور على المصفوفة الثنائية:
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// طباعة جميع العناصر
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + "\t");
    }
    System.out.println();
}
3. مصفوفات غير منتظمة (Jagged Arrays):
// مصفوفة بأطوال مختلفة
int[][] jagged = new int[3][];
jagged[0] = new int[2];
jagged[1] = new int[4];
jagged[2] = new int[3];
4. مثال عملي - جدول الضرب:
int[][] multiplicationTable = new int[10][10];

for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10; j++) {
        multiplicationTable[i][j] = (i + 1) * (j + 1);
    }
}

// طباعة الجدول
for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10; j++) {
        System.out.printf("%4d", multiplicationTable[i][j]);
    }
    System.out.println();
}

الدوال Methods

الدوال في Java:

الدوال (Methods) هي كتل من الكود قابلة لإعادة الاستخدام تؤدي وظيفة محددة.

1. تعريف دالة بسيطة:
public class MethodsExample {
    // دالة بلا معاملات وبلا قيمة إرجاع
    public static void greet() {
        System.out.println("مرحباً!");
    }
    
    // دالة بمعاملات
    public static void greetPerson(String name) {
        System.out.println("مرحباً " + name + "!");
    }
    
    // دالة تُرجع قيمة
    public static int add(int a, int b) {
        return a + b;
    }
    
    public static void main(String[] args) {
        greet();
        greetPerson("أحمد");
        int result = add(5, 3);
        System.out.println("النتيجة: " + result); // 8
    }
}
2. أنواع الدوال:
  • Static Methods: تنتمي للكلاس وليس للكائن
  • Instance Methods: تنتمي لكائن محدد
  • Void Methods: لا ترجع قيمة
  • Return Methods: ترجع قيمة محددة
3. مثال شامل:
public class Calculator {
    public static int multiply(int x, int y) {
        return x * y;
    }
    
    public static double divide(double a, double b) {
        if (b != 0) {
            return a / b;
        } else {
            System.out.println("لا يمكن القسمة على صفر!");
            return 0;
        }
    }
    
    public static void printResult(String operation, double result) {
        System.out.println(operation + " = " + result);
    }
}

معاملات الدوال Overloading

Method Overloading في Java:

Method Overloading يعني تعريف عدة دوال بنفس الاسم لكن بمعاملات مختلفة.

مثال على Method Overloading:
public class MathUtils {
    // دالة add للمتغيرات int
    public static int add(int a, int b) {
        return a + b;
    }
    
    // نفس الاسم لكن مع double
    public static double add(double a, double b) {
        return a + b;
    }
    
    // نفس الاسم لكن بثلاثة معاملات
    public static int add(int a, int b, int c) {
        return a + b + c;
    }
    
    public static void main(String[] args) {
        System.out.println(add(5, 3));        // 8
        System.out.println(add(5.5, 3.2));    // 8.7
        System.out.println(add(1, 2, 3));     // 6
    }
}
قواعد Method Overloading:
  • يجب أن يكون الاسم نفسه
  • يجب أن تختلف المعاملات في: العدد، النوع، أو الترتيب
  • لا يمكن الاعتماد فقط على نوع الإرجاع
مثال عملي - طباعة:
public class Printer {
    public static void print(int value) {
        System.out.println("عدد صحيح: " + value);
    }
    
    public static void print(double value) {
        System.out.println("عدد عشري: " + value);
    }
    
    public static void print(String text) {
        System.out.println("نص: " + text);
    }
    
    public static void print(int[] array) {
        System.out.print("مصفوفة: ");
        for (int num : array) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

مفهوم الكائنات والكلاسات

البرمجة الكائنية التوجه (OOP):

Java لغة برمجة كائنية التوجه، حيث كل شيء في Java هو كائن (Object) أو ينتمي لكلاس (Class).

مفاهيم OOP الأساسية:
  • Class (الكلاس): قالب لإنشاء الكائنات
  • Object (الكائن): مثال محدد من الكلاس
  • Encapsulation (التغليف): إخفاء تفاصيل التنفيذ
  • Inheritance (الوراثة): نقل الصفات من كلاس لآخر
  • Polymorphism (تعدد الأشكال): نفس الواجهة، تنفيذ مختلف
مثال بسيط:
// تعريف كلاس
public class Car {
    // Attributes (الخصائص)
    String brand;
    String color;
    int year;
    
    // Methods (الوظائف)
    public void start() {
        System.out.println("السيارة تعمل");
    }
    
    public void stop() {
        System.out.println("السيارة متوقفة");
    }
}

// إنشاء كائنات
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.brand = "Toyota";
        myCar.color = "أحمر";
        myCar.year = 2023;
        
        myCar.start();
        myCar.stop();
    }
}

البنائين Constructors

Constructors في Java:

Constructor هو دالة خاصة تُستدعى تلقائياً عند إنشاء كائن جديد من الكلاس.

1. Default Constructor:
public class Person {
    String name;
    int age;
    
    // Default Constructor (يُنشأ تلقائياً إذا لم نحدده)
    public Person() {
        name = "غير محدد";
        age = 0;
    }
}
2. Parameterized Constructor:
public class Person {
    String name;
    int age;
    
    // Constructor بمعاملات
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void display() {
        System.out.println("الاسم: " + name + ", العمر: " + age);
    }
    
    public static void main(String[] args) {
        Person person1 = new Person("أحمد", 25);
        person1.display();
    }
}
3. Constructor Overloading:
public class Rectangle {
    int width;
    int height;
    
    // Constructor بدون معاملات
    public Rectangle() {
        this.width = 1;
        this.height = 1;
    }
    
    // Constructor بمعامل واحد (مربع)
    public Rectangle(int side) {
        this.width = side;
        this.height = side;
    }
    
    // Constructor بمعاملين
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
}
ملاحظة: الكلمة المفتاحية this تشير إلى الكائن الحالي.

التغليف Encapsulation

Encapsulation في Java:

Encapsulation يعني إخفاء تفاصيل التنفيذ وإتاحة الوصول للبيانات من خلال methods محددة.

Access Modifiers:
  • public: متاح من أي مكان
  • private: متاح فقط داخل الكلاس نفسه
  • protected: متاح داخل الكلاس والكلاسات الموروثة
  • default: متاح داخل نفس الحزمة (package)
مثال على Encapsulation:
public class BankAccount {
    // Private attributes
    private double balance;
    private String accountNumber;
    
    // Constructor
    public BankAccount(String accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        if (initialBalance >= 0) {
            this.balance = initialBalance;
        } else {
            this.balance = 0;
        }
    }
    
    // Getter method
    public double getBalance() {
        return balance;
    }
    
    // Setter method مع التحقق
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("تم الإيداع: " + amount);
        } else {
            System.out.println("المبلغ غير صحيح!");
        }
    }
    
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("تم السحب: " + amount);
        } else {
            System.out.println("المبلغ غير متاح!");
        }
    }
}

الوراثة Inheritance

Inheritance في Java:

Inheritance تسمح لكلاس بالحصول على صفات ووظائف كلاس آخر.

مثال على Inheritance:
// Parent Class (الكلاس الأب)
public class Animal {
    String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void eat() {
        System.out.println(name + " يأكل");
    }
    
    public void sleep() {
        System.out.println(name + " ينام");
    }
}

// Child Class (الكلاس الابن)
public class Dog extends Animal {
    String breed;
    
    public Dog(String name, String breed) {
        super(name); // استدعاء constructor الأب
        this.breed = breed;
    }
    
    public void bark() {
        System.out.println(name + " ينبح");
    }
    
    // Method Overriding
    @Override
    public void eat() {
        System.out.println(name + " يأكل الطعام المخصص للكلاب");
    }
}

// استخدام
public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog("ريكس", "جيرمن شيبرد");
        myDog.eat();    // من الأب (معدّل)
        myDog.sleep();  // من الأب
        myDog.bark();   // خاص بالكلب
    }
}
كلمات مفتاحية مهمة:
  • extends: للوراثة
  • super: للإشارة للكلاس الأب
  • @Override: لتجاوز method من الأب

تعدد الأشكال Polymorphism

Polymorphism في Java:

Polymorphism يعني قدرة الكائنات على أخذ أشكال متعددة، نفس الواجهة لكن تنفيذ مختلف.

Runtime Polymorphism (Method Overriding):
public class Shape {
    public void draw() {
        System.out.println("رسم شكل");
    }
}

public class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("رسم دائرة");
    }
}

public class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.println("رسم مستطيل");
    }
}

// استخدام Polymorphism
public class Main {
    public static void main(String[] args) {
        Shape shape1 = new Circle();
        Shape shape2 = new Rectangle();
        
        shape1.draw(); // رسم دائرة
        shape2.draw(); // رسم مستطيل
    }
}
مثال عملي:
public class Employee {
    protected String name;
    
    public Employee(String name) {
        this.name = name;
    }
    
    public double calculateSalary() {
        return 0;
    }
}

public class FullTimeEmployee extends Employee {
    private double monthlySalary;
    
    public FullTimeEmployee(String name, double monthlySalary) {
        super(name);
        this.monthlySalary = monthlySalary;
    }
    
    @Override
    public double calculateSalary() {
        return monthlySalary;
    }
}

public class PartTimeEmployee extends Employee {
    private double hourlyRate;
    private int hoursWorked;
    
    public PartTimeEmployee(String name, double hourlyRate, int hoursWorked) {
        super(name);
        this.hourlyRate = hourlyRate;
        this.hoursWorked = hoursWorked;
    }
    
    @Override
    public double calculateSalary() {
        return hourlyRate * hoursWorked;
    }
}

الواجهات Interfaces

Interfaces في Java:

Interface هو عقد يحدد ما يجب أن تفعله الكلاسات دون تحديد كيفية التنفيذ.

تعريف Interface:
// تعريف Interface
public interface Drawable {
    void draw(); // method بلا تنفيذ (implicitly public abstract)
    void resize(int size);
}

// تنفيذ Interface
public class Circle implements Drawable {
    private int radius;
    
    public Circle(int radius) {
        this.radius = radius;
    }
    
    @Override
    public void draw() {
        System.out.println("رسم دائرة بنصف قطر: " + radius);
    }
    
    @Override
    public void resize(int size) {
        this.radius = size;
        System.out.println("تم تغيير نصف القطر إلى: " + size);
    }
}
Java 8+ - Default Methods:
public interface Calculator {
    int add(int a, int b);
    
    // Default method (له تنفيذ افتراضي)
    default int multiply(int a, int b) {
        return a * b;
    }
    
    // Static method
    static void printInfo() {
        System.out.println("آلة حاسبة");
    }
}
تنفيذ عدة Interfaces:
public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("البطة تطير");
    }
    
    @Override
    public void swim() {
        System.out.println("البطة تسبح");
    }
}

الكلاسات المجردة Abstract Classes

Abstract Classes في Java:

Abstract Class هي كلاس لا يمكن إنشاء كائنات منه مباشرة، ويحتوي على methods مجردة و/أو عادية.

مثال على Abstract Class:
// Abstract Class
public abstract class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    // Concrete method (له تنفيذ)
    public void sleep() {
        System.out.println(name + " ينام");
    }
    
    // Abstract method (لا له تنفيذ)
    public abstract void makeSound();
}

// تنفيذ Abstract Class
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    
    @Override
    public void makeSound() {
        System.out.println(name + " ينبح: واو واو!");
    }
}

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
    
    @Override
    public void makeSound() {
        System.out.println(name + " يموء: مياو!");
    }
}
الفرق بين Abstract Class و Interface:
Abstract Class Interface
يمكن أن تحتوي على متغيرات instance يمكن أن تحتوي على constants فقط
يمكن أن تحتوي على methods عادية ومجردة كل methods مجردة (قبل Java 8)
تدعم واحدة فقط (single inheritance) تدعم عدة interfaces (multiple inheritance)
يمكن أن يكون لها constructor لا يمكن أن يكون لها constructor

String و StringBuffer

String في Java:

String هي فئة في Java لتمثيل النصوص، وهي immutable (غير قابلة للتعديل).

1. إنشاء Strings:
String str1 = "مرحباً";
String str2 = new String("العالم");
String str3 = str1 + " " + str2; // "مرحباً العالم"
2. Methods مهمة في String:
String text = "Hello World";

System.out.println(text.length());        // 11
System.out.println(text.charAt(0));       // 'H'
System.out.println(text.substring(0, 5)); // "Hello"
System.out.println(text.toUpperCase());   // "HELLO WORLD"
System.out.println(text.toLowerCase());   // "hello world"
System.out.println(text.contains("World")); // true
System.out.println(text.replace("World", "Java")); // "Hello Java"
3. StringBuffer (قابل للتعديل):
StringBuffer sb = new StringBuffer("مرحباً");
sb.append(" بالعالم");
sb.insert(7, " ");
sb.reverse();
System.out.println(sb.toString());

ArrayList - الجزء الأول

ArrayList في Java:

ArrayList هي قائمة ديناميكية يمكنها النمو أو التقلص حسب الحاجة، أفضل من Arrays في معظم الحالات.

1. إنشاء ArrayList:
import java.util.ArrayList;

ArrayList<String> names = new ArrayList<>();
ArrayList<Integer> numbers = new ArrayList<Integer>();
2. العمليات الأساسية:
ArrayList<String> list = new ArrayList<>();

// إضافة عناصر
list.add("أحمد");
list.add("محمد");
list.add("فاطمة");

// الحصول على العنصر
String name = list.get(0); // "أحمد"

// الحجم
int size = list.size(); // 3

// حذف عنصر
list.remove(0); // حذف "أحمد"

// التحقق من وجود عنصر
boolean exists = list.contains("محمد"); // true
3. المرور على ArrayList:
// باستخدام for-each
for (String name : list) {
    System.out.println(name);
}

// باستخدام for عادية
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

ArrayList - الجزء الثاني

عمليات متقدمة في ArrayList:

1. إضافة في موضع محدد:
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(30);
numbers.add(2, 20); // إضافة 20 في الفهرس 2
// النتيجة: [10, 30, 20]
2. تحديث قيمة:
numbers.set(0, 15); // تغيير العنصر في الفهرس 0 إلى 15
3. حذف جميع العناصر:
numbers.clear(); // حذف جميع العناصر
4. مثال شامل:
import java.util.ArrayList;
import java.util.Collections;

ArrayList<Integer> scores = new ArrayList<>();
scores.add(85);
scores.add(92);
scores.add(78);
scores.add(95);

// ترتيب القائمة
Collections.sort(scores);

// البحث
int index = Collections.binarySearch(scores, 85);

// العثور على أكبر وأصغر قيمة
int max = Collections.max(scores);
int min = Collections.min(scores);

HashMap و HashTable

HashMap في Java:

HashMap تخزن البيانات في أزواج Key-Value، وتوفر وصول سريع للبيانات.

1. إنشاء واستخدام HashMap:
import java.util.HashMap;

HashMap<String, Integer> ages = new HashMap<>();

// إضافة عناصر
ages.put("أحمد", 25);
ages.put("محمد", 30);
ages.put("فاطمة", 22);

// الحصول على قيمة
int age = ages.get("أحمد"); // 25

// التحقق من وجود مفتاح
boolean exists = ages.containsKey("أحمد"); // true

// حذف عنصر
ages.remove("محمد");

// الحجم
int size = ages.size();
2. المرور على HashMap:
// المرور على Keys
for (String name : ages.keySet()) {
    System.out.println(name + ": " + ages.get(name));
}

// المرور على Entries
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}
3. HashTable vs HashMap:
  • HashMap: غير متزامن، أسرع، يسمح بقيمة null
  • HashTable: متزامن، أبطأ، لا يسمح بقيمة null

معالجة الاستثناءات Exceptions

Exception Handling في Java:

Exception Handling يسمح للبرنامج بالتعامل مع الأخطاء بشكل مناسب بدلاً من التوقف.

1. try-catch:
try {
    int result = 10 / 0; // سيحدث ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("خطأ: لا يمكن القسمة على صفر");
    System.out.println("التفاصيل: " + e.getMessage());
}
2. try-catch-finally:
try {
    // كود قد يسبب خطأ
    int[] arr = new int[5];
    arr[10] = 100; // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("فهرس خارج النطاق");
} finally {
    // يُنفذ دائماً
    System.out.println("تم الانتهاء من try-catch");
}
3. Multiple catch blocks:
try {
    // كود
} catch (ArithmeticException e) {
    System.out.println("خطأ حسابي");
} catch (NullPointerException e) {
    System.out.println("مرجع فارغ");
} catch (Exception e) {
    System.out.println("خطأ عام: " + e.getMessage());
}

try-catch-finally

مزيد من التفاصيل حول Exception Handling:

1. Custom Exceptions:
// إنشاء Exception مخصص
public class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message);
    }
}

// استخدام
public class Person {
    private int age;
    
    public void setAge(int age) throws InvalidAgeException {
        if (age < 0 || age > 150) {
            throw new InvalidAgeException("العمر غير صحيح: " + age);
        }
        this.age = age;
    }
}
2. throws Keyword:
public void readFile(String filename) throws IOException {
    FileReader file = new FileReader(filename);
    // ...
}
3. مثال عملي شامل:
import java.util.Scanner;

public class ExceptionExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        try {
            System.out.print("أدخل عدداً: ");
            int number = scanner.nextInt();
            
            System.out.print("أدخل عدداً آخر: ");
            int divisor = scanner.nextInt();
            
            int result = number / divisor;
            System.out.println("النتيجة: " + result);
            
        } catch (java.util.InputMismatchException e) {
            System.out.println("خطأ: يجب إدخال عدد صحيح");
        } catch (ArithmeticException e) {
            System.out.println("خطأ: لا يمكن القسمة على صفر");
        } catch (Exception e) {
            System.out.println("حدث خطأ غير متوقع: " + e.getMessage());
        } finally {
            scanner.close();
            System.out.println("تم إغلاق الماسح الضوئي");
        }
    }
}

الملفات File I/O

File Input/Output في Java:

Java توفر عدة طرق للتعامل مع الملفات: قراءة وكتابة البيانات.

1. قراءة من ملف باستخدام FileReader:
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;

try {
    FileReader fileReader = new FileReader("data.txt");
    BufferedReader reader = new BufferedReader(fileReader);
    
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
    
    reader.close();
} catch (IOException e) {
    System.out.println("خطأ في قراءة الملف: " + e.getMessage());
}
2. الكتابة إلى ملف:
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;

try {
    FileWriter fileWriter = new FileWriter("output.txt");
    BufferedWriter writer = new BufferedWriter(fileWriter);
    
    writer.write("مرحباً بالعالم");
    writer.newLine();
    writer.write("هذا سطر جديد");
    
    writer.close();
} catch (IOException e) {
    System.out.println("خطأ في الكتابة: " + e.getMessage());
}
3. استخدام try-with-resources (موصى به):
try (FileReader fr = new FileReader("input.txt");
     BufferedReader br = new BufferedReader(fr)) {
    
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
} // الملف يُغلق تلقائياً

Multithreading الأساسيات

Multithreading في Java:

Multithreading يسمح بتنفيذ عدة عمليات في نفس الوقت، مما يحسن الأداء.

1. إنشاء Thread بطريقتين:
// الطريقة 1: Extend Thread
public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Thread: " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

// الطريقة 2: Implement Runnable
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Runnable: " + i);
        }
    }
}

// الاستخدام
public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        thread1.start();
        
        Thread thread2 = new Thread(new MyRunnable());
        thread2.start();
    }
}
2. Thread Methods:
Thread thread = new Thread(() -> {
    System.out.println("Thread يعمل");
});

thread.start();   // بدء Thread
thread.join();    // انتظار انتهاء Thread
thread.sleep(1000); // توقيف Thread لمدة معينة

Swing و GUI

Java Swing:

Swing هي مكتبة Java لإنشاء واجهات المستخدم الرسومية (GUI).

مثال بسيط - نافذة:
import javax.swing.*;

public class SimpleGUI {
    public static void main(String[] args) {
        JFrame frame = new JFrame("تطبيق بسيط");
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        JLabel label = new JLabel("مرحباً بكم!");
        JButton button = new JButton("اضغط هنا");
        
        button.addActionListener(e -> {
            label.setText("تم الضغط على الزر!");
        });
        
        frame.add(label);
        frame.add(button);
        frame.setLayout(new FlowLayout());
        frame.setVisible(true);
    }
}
مكونات Swing الأساسية:
  • JFrame: النافذة الرئيسية
  • JLabel: نص أو صورة
  • JButton: زر
  • JTextField: حقل إدخال نص
  • JTextArea: منطقة نص كبيرة
  • JPanel: لوحة لتجميع المكونات

مشروع تطبيقي شامل

مشروع: نظام إدارة طلاب

مشروع شامل يجمع معظم المفاهيم التي تعلمناها في الكورس.

البنية المقترحة:
// Student Class
public class Student {
    private String name;
    private int id;
    private ArrayList<Double> grades;
    
    public Student(String name, int id) {
        this.name = name;
        this.id = id;
        this.grades = new ArrayList<>();
    }
    
    public void addGrade(double grade) {
        if (grade >= 0 && grade <= 100) {
            grades.add(grade);
        }
    }
    
    public double getAverage() {
        if (grades.isEmpty()) return 0;
        double sum = 0;
        for (double grade : grades) {
            sum += grade;
        }
        return sum / grades.size();
    }
    
    // Getters and Setters
    // ...
}

// StudentManager Class
import java.util.ArrayList;
import java.util.HashMap;

public class StudentManager {
    private HashMap<Integer, Student> students;
    
    public StudentManager() {
        this.students = new HashMap<>();
    }
    
    public void addStudent(Student student) {
        students.put(student.getId(), student);
    }
    
    public Student getStudent(int id) {
        return students.get(id);
    }
    
    public void displayAllStudents() {
        for (Student student : students.values()) {
            System.out.println(student);
        }
    }
}

// Main Class
public class Main {
    public static void main(String[] args) {
        StudentManager manager = new StudentManager();
        
        Student student1 = new Student("أحمد", 1001);
        student1.addGrade(85);
        student1.addGrade(90);
        student1.addGrade(88);
        
        manager.addStudent(student1);
        manager.displayAllStudents();
    }
}
ميزات المشروع:
  • استخدام Classes و Objects
  • Encapsulation (Private attributes, Public methods)
  • Collections (ArrayList, HashMap)
  • Exception Handling
  • File I/O (حفظ وقراءة البيانات)
  • GUI (واجهة مستخدم بسيطة)
تهانينا! لقد أكملت كورس Java الأساسي. استمر في الممارسة والبناء!