بناء البرمجيات - المعمل 2: مجموعات جافا، المصفوفات، الحلقات والأصناف
7 دقائق قراءة
شرائح الدرس
1 / 15
جامعة المنصورة - كلية الحاسبات والمعلومات
المقرر: بناء البرمجيات (الفرقة 4)
🎯 أهداف المعمل
يبني هذا المعمل على مفاهيم جافا الأساسية لاستكشاف:
- فهم القيم البدائية (Primitive) مقابل القيم الكائنية (Object)، وكيف تدير جافا الذاكرة
- إتقان الحلقات (
for،while) وأنماط التكرار - العمل مع المصفوفات (Arrays) وفهم فهرسة المصفوفات (Indexing)
- تعريف واستخدام الأصناف (Classes) والكائنات (Objects) (البرمجة كائنية التوجه)
- فهم المراجع (References) مقابل القيم (Values)
- العمل مع الباني (Constructors) والدوال (Methods)
- استخدام الكلمة المفتاحية
staticبفعالية - التمييز بين تغيير محتوى القيم (Mutating) وإعادة إسناد المتغيرات (Reassigning)
- العمل مع المراجع الثابتة (Immutable) باستخدام الكلمة المفتاحية
final - إتقان إطار مجموعات جافا (Java Collections Framework) (القائمة List، المجموعة Set، الخريطة Map)
- تطبيق تقنيات تصحيح الأخطاء (Debugging) وأفضل الممارسات
- حل مسائل برمجية من واقع الحياة
📋 هيكل المعمل
- الجزء 0: أسلوب البرمجة الجيد
- الجزء 1: الحلقات والتكرار
- الجزء 2: المصفوفات
- الجزء 3: تقنيات تصحيح الأخطاء
- الجزء 4: الأصناف والكائنات (البرمجة كائنية التوجه)
- الجزء 5: القيم البدائية مقابل القيم الكائنية والمراجع
- الجزء 6: الكلمة المفتاحية
static - الجزء 7: التغيير مقابل إعادة الإسناد
- الجزء 8: المراجع الثابتة باستخدام
final - الجزء 9: إطار مجموعات جافا
- الجزء 10: مشاريع تطبيقية
🎨 الجزء 0: أسلوب البرمجة الجيد
القاعدة رقم 1: استخدم أسماء متغيرات ذات معنى
// ❌ BAD - Cryptic names
String a1;
int a2;
double b;
// ✅ GOOD - Descriptive names
String firstName;
String lastName;
int temperature;
double salary;القاعدة رقم 2: استخدم مسافات بادئة (Indentation) صحيحة
// ❌ BAD - No indentation
public static void main(String[] args) {
int x = 5;
x = x * x;
if (x > 20) {
System.out.println(x + " is greater than 20");
}
}
// ✅ GOOD - Proper indentation
public static void main(String[] args) {
int x = 5;
x = x * x;
if (x > 20) {
System.out.println(x + " is greater than 20");
}
}نصيحة Eclipse: اضغط Ctrl+Shift+F لتنسيق الكود تلقائيًا!
القاعدة رقم 3: استخدم المسافات لتحسين القابلية للقراءة
// ❌ BAD - Cramped
double cel=fahr*42.0/(13.0-7.0);
// ✅ GOOD - Breathing room
double cel = fahr * 42.0 / (13.0 - 7.0);القاعدة رقم 4: لا تكرّر المنطق
// ❌ BAD - Redundant tests
if (basePay < 8.0) {
System.out.println("Error: Pay too low");
} else if (hours > 60) {
System.out.println("Error: Too many hours");
} else if (basePay >= 8.0 && hours <= 60) { // Redundant!
// Calculate pay
}
// ✅ GOOD - Simple else
if (basePay < 8.0) {
System.out.println("Error: Pay too low");
} else if (hours > 60) {
System.out.println("Error: Too many hours");
} else {
// Calculate pay - we know it's valid here!
}القاعدة رقم 5: استخدم الأقواس المعقوفة دائمًا
// ❌ DANGEROUS - Easy to make mistakes
for (int i = 0; i < 5; i++)
System.out.println("Hi");
System.out.println("Bye"); // This is NOT in the loop!
// ✅ GOOD - Clear intent
for (int i = 0; i < 5; i++) {
System.out.println("Hi");
System.out.println("Bye");
}🔁 الجزء 1: الحلقات والتكرار
لماذا نستخدم الحلقات؟
// ❌ Without loops - repetitive and limited
System.out.println("Student #1");
System.out.println("Student #2");
System.out.println("Student #3");
// What if you want 200 students?
// ✅ With loops - flexible and scalable
for (int i = 1; i <= 200; i++) {
System.out.println("Student #" + i);
}التمرين 1.1: حلقة while
الصيغة العامة:
while (condition) {
statements
}مثال:
public class WhileExample {
public static void main(String[] args) {
int i = 0;
while (i < 3) {
System.out.println("Count: " + i);
i = i + 1; // CRITICAL: Must change i or loop runs forever!
}
}
}التمرين 1.2: حلقة for
الصيغة العامة:
for (initialization; condition; update) {
statements
}مثال:
public class ForExample {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println("Count: " + i);
}
}
}التمرين 1.3: جُمل التحكم في الحلقات
break - الخروج من الحلقة فورًا:
public class BreakExample {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println("Number: " + i);
if (i == 50) {
break; // Stop at 50
}
}
System.out.println("Done!");
}
}continue - الانتقال إلى التكرار التالي:
public class ContinueExample {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
if (i == 5) {
continue; // Skip printing for i = 5
}
System.out.println("Number: " + i);
}
}
}📊 الجزء 2: المصفوفات (Arrays)
ما هي المصفوفة؟
المصفوفة (Array) هي قائمة مفهرسة من القيم من نفس النوع.
Array: [5.0, 2.44, 9.01, 1.0, -9.5]
Index: 0 1 2 3 4التمرين 2.1: إنشاء المصفوفات واستخدامها
// Method 1: Declare size, then assign values
int[] values = new int[5];
values[0] = 12;
values[1] = 24;
values[2] = -23;
values[3] = 47;
values[4] = 100;
// Method 2: Initialize with values
int[] numbers = {12, 24, -23, 47, 100};
// Method 3: Variable size
int size = 10;
double[] data = new double[size];التمرين 2.2: فهرس المصفوفة مقابل قيمة المصفوفة ⚠️
مفهوم حاسم:
public class ArrayIndexVsValue {
public static void main(String[] args) {
int[] values = {99, 100, 101};
System.out.println(values[0]); // 99 (VALUE at index 0)
System.out.println(0); // 0 (just the number 0)
// Visual representation:
// Values: 99 100 101
// Indexes: 0 1 2
}
}التمرين 2.3: خوارزميات المصفوفات الشائعة
الخوارزمية 1: إيجاد فهرس القيمة الصغرى
public class FindMinIndex {
public static int getMinIndex(int[] values) {
int minValue = Integer.MAX_VALUE;
int minIndex = -1;
for (int i = 0; i < values.length; i++) {
if (values[i] < minValue) {
minValue = values[i];
minIndex = i;
}
}
return minIndex;
}
public static void main(String[] args) {
int[] times = {152, 148, 156, 145, 150}; // Marathon times
int fastestRunner = getMinIndex(times);
System.out.println("Fastest runner: #" + fastestRunner);
System.out.println("Time: " + times[fastestRunner] + " minutes");
}
}الخوارزمية 2: إيجاد فهرس ثاني أصغر قيمة
public class FindSecondMin {
public static int getMinIndex(int[] values) {
int minValue = Integer.MAX_VALUE;
int minIndex = -1;
for (int i = 0; i < values.length; i++) {
if (values[i] < minValue) {
minValue = values[i];
minIndex = i;
}
}
return minIndex;
}
public static int getSecondMinIndex(int[] values) {
int secondIdx = -1;
int minIdx = getMinIndex(values);
for (int i = 0; i < values.length; i++) {
if (i == minIdx) {
continue; // Skip the minimum
}
if (secondIdx == -1 || values[i] < values[secondIdx]) {
secondIdx = i;
}
}
return secondIdx;
}
}🐛 الجزء 3: تقنيات تصحيح الأخطاء (Debugging)
التقنية 1: جُمل الطباعة الاستراتيجية
public class DebugExample {
public static int findMin(int[] vals) {
int minVal = Integer.MAX_VALUE;
System.out.println("Starting search...");
for (int i = 0; i < vals.length; i++) {
System.out.println("Checking index " + i + ": " + vals[i]);
if (vals[i] < minVal) {
System.out.println(" New minimum found!");
minVal = vals[i];
}
}
return minVal;
}
}التقنية 2: نسّق الكود الخاص بك
تذكّر: Ctrl+Shift+F في Eclipse ينسّق الكود تلقائيًا!
🏗️ الجزء 4: الأصناف والكائنات (Classes and Objects)
لماذا البرمجة كائنية التوجه (OOP)؟
// ❌ BAD - Managing 500 students with primitives
String nameAhmed;
int ageAhmed;
double gradeAhmed;
String nameFatima;
int ageFatima;
double gradeFatima;
// ... 498 more? Impractical!
// ✅ GOOD - Use a class
public class Student {
String name;
int age;
double grade;
}
Student[] classroom = new Student[500];التمرين 4.1: تعريف صنف (Class)
public class Student {
// FIELDS (data)
String name;
int age;
double gpa;
String major;
int creditHours;
// CONSTRUCTOR
Student(String studentName, int studentAge, String studentMajor) {
name = studentName;
age = studentAge;
major = studentMajor;
gpa = 0.0;
creditHours = 0;
}
// METHODS (behaviors)
void displayInfo() {
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Major: " + major);
System.out.println("GPA: " + gpa);
}
void updateGPA(double newGPA) {
if (newGPA >= 0.0 && newGPA <= 4.0) {
gpa = newGPA;
System.out.println(name + "'s GPA updated to " + gpa);
}
}
void enrollCourse(int credits) {
creditHours += credits;
System.out.println(name + " enrolled in " + credits + " credit hours");
}
}التمرين 4.2: إنشاء الكائنات (Objects)
public class University {
public static void main(String[] args) {
// Create Student objects
Student ahmed = new Student("Ahmed Ali", 20, "Computer Science");
Student fatima = new Student("Fatima Hassan", 19, "Engineering");
// Access fields
System.out.println(ahmed.name); // "Ahmed Ali"
System.out.println(fatima.major); // "Engineering"
// Call methods
ahmed.displayInfo();
ahmed.updateGPA(3.8);
fatima.enrollCourse(15);
}
}🔗 الجزء 5: المراجع مقابل القيم (References vs Values)
كيف تخزّن جافا البيانات
القيم البدائية (Primitives) = تُخزَّن مباشرة
int x = 5;
int y = x; // y gets a COPY
x = 10;
System.out.println(x); // 10
System.out.println(y); // 5 (unchanged)الكائنات (Objects) = تُخزَّن كمراجع (References)
Student s1 = new Student("Ahmed", 20, "CS");
Student s2 = s1; // s2 points to SAME object
s1.gpa = 3.8;
System.out.println(s1.gpa); // 3.8
System.out.println(s2.gpa); // 3.8 (same object!)التمرين 5.1: عامل المقارنة ==
Student s1 = new Student("Ahmed", 20, "CS");
Student s2 = new Student("Ahmed", 20, "CS");
System.out.println(s1 == s2); // false! (different objects)
Student s3 = s1;
System.out.println(s1 == s3); // true! (same object)التمرين 5.2: معاملات الدوال (Method Parameters)
public class ReferenceTest {
public static void modifyPrimitive(int x) {
x = 99; // Only changes local copy
}
public static void modifyObject(Student s) {
s.gpa = 4.0; // Modifies the actual object!
}
public static void main(String[] args) {
int num = 5;
modifyPrimitive(num);
System.out.println(num); // 5 (unchanged)
Student ahmed = new Student("Ahmed", 20, "CS");
modifyObject(ahmed);
System.out.println(ahmed.gpa); // 4.0 (changed!)
}
}🔒 الجزء 6: الكلمة المفتاحية static
الحقول الساكنة (Static Fields) - مشتركة بين جميع النُّسخ
public class Student {
static int totalStudents = 0; // SHARED by all
String name; // UNIQUE to each
Student(String studentName) {
name = studentName;
totalStudents++;
}
}
public class TestStatic {
public static void main(String[] args) {
System.out.println(Student.totalStudents); // 0
Student s1 = new Student("Ahmed");
System.out.println(Student.totalStudents); // 1
Student s2 = new Student("Fatima");
System.out.println(Student.totalStudents); // 2
System.out.println(s1.totalStudents); // 2
System.out.println(s2.totalStudents); // 2 (shared!)
}
}الدوال الساكنة (Static Methods)
public class MathHelper {
// Static method - can call without creating object
static int add(int a, int b) {
return a + b;
}
}
public class Test {
public static void main(String[] args) {
int result = MathHelper.add(5, 3); // No object needed!
System.out.println(result); // 8
}
}لماذا main دالة ساكنة (static)؟
public class Program {
public static void main(String[] args) {
// main is static because Java needs to call it
// BEFORE any objects are created!
System.out.println("Program started");
}
}🔄 الجزء 7: التغيير مقابل إعادة الإسناد (Mutation vs Reassignment)
إعادة الإسناد (Reassignment) = تغيير ما يشير إليه المتغير
int x = 5;
x = 10; // REASSIGNMENT: x now points to 10التغيير (Mutation) = تغيير محتوى الكائن
Student ahmed = new Student("Ahmed", 20, "CS");
ahmed.gpa = 3.8; // MUTATION: changing object's state
// ahmed still points to same Student object🔐 الجزء 8: الكلمة المفتاحية final
public class FinalExample {
public static void main(String[] args) {
// final with primitive
final int MAX_STUDENTS = 100;
// MAX_STUDENTS = 200; // ERROR!
// final with array
final int[] scores = {85, 90, 78};
scores[0] = 95; // ✅ OK: mutating contents
// scores = new int[]{1, 2, 3}; // ❌ ERROR: reassignment
// final with object
final Student ahmed = new Student("Ahmed", 20, "CS");
ahmed.gpa = 3.8; // ✅ OK: mutating object
// ahmed = new Student(...); // ❌ ERROR: reassignment
}
}📦 الجزء 9: مجموعات جافا (Java Collections)
القوائم (Lists)
import java.util.*;
public class ListExample {
public static void main(String[] args) {
List<String> courses = new ArrayList<>();
courses.add("Math");
courses.add("Physics");
courses.add("Programming");
System.out.println(courses.size()); // 3
System.out.println(courses.get(0)); // "Math"
for (String course : courses) {
System.out.println(course);
}
}
}المجموعات (Sets)
import java.util.*;
public class SetExample {
public static void main(String[] args) {
Set<Integer> ids = new HashSet<>();
ids.add(101);
ids.add(102);
ids.add(101); // Duplicate - won't be added
System.out.println(ids.size()); // 2, not 3!
System.out.println(ids.contains(101)); // true
}
}الخرائط (Maps)
import java.util.*;
public class MapExample {
public static void main(String[] args) {
Map<String, Double> grades = new HashMap<>();
grades.put("Ahmed", 3.8);
grades.put("Fatima", 3.9);
grades.put("Omar", 3.7);
System.out.println(grades.get("Ahmed")); // 3.8
for (Map.Entry<String, Double> entry : grades.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}🚀 مشروع تطبيقي: نظام إدارة الطلاب
import java.util.*;
public class Student {
String name;
int id;
double gpa;
Student(String name, int id, double gpa) {
this.name = name;
this.id = id;
this.gpa = gpa;
}
}
public class StudentManagementSystem {
private List<Student> students;
private Map<Integer, Student> studentMap;
public StudentManagementSystem() {
students = new ArrayList<>();
studentMap = new HashMap<>();
}
public void addStudent(Student student) {
students.add(student);
studentMap.put(student.id, student);
System.out.println("Added: " + student.name);
}
public Student findStudent(int id) {
return studentMap.get(id);
}
public double getAverageGPA() {
double sum = 0;
for (Student student : students) {
sum += student.gpa;
}
return sum / students.size();
}
public Student getTopStudent() {
Student top = students.get(0);
for (Student student : students) {
if (student.gpa > top.gpa) {
top = student;
}
}
return top;
}
public void displayAll() {
System.out.println("\n=== Student Report ===");
System.out.println("Total students: " + students.size());
for (Student student : students) {
System.out.println(student.id + ": " + student.name +
" (GPA: " + student.gpa + ")");
}
System.out.println("Average GPA: " + getAverageGPA());
Student top = getTopStudent();
System.out.println("Top student: " + top.name);
}
public static void main(String[] args) {
StudentManagementSystem sms = new StudentManagementSystem();
sms.addStudent(new Student("Ahmed Ali", 101, 3.8));
sms.addStudent(new Student("Fatima Hassan", 102, 3.9));
sms.addStudent(new Student("Omar Ibrahim", 103, 3.7));
sms.addStudent(new Student("Mona Khalil", 104, 3.95));
sms.displayAll();
Student found = sms.findStudent(102);
if (found != null) {
System.out.println("\nFound student: " + found.name);
}
}
}✅ قائمة تحقق المعمل
الأجزاء 1-3: الأساسيات
- كتابة حلقات
forوwhileبشكل صحيح - إنشاء المصفوفات والتعامل معها
- تنفيذ خوارزميات المصفوفات (إيجاد الأصغر، إيجاد ثاني أصغر)
- استخدام تقنيات تصحيح الأخطاء
الأجزاء 4-6: البرمجة كائنية التوجه
- تعريف الأصناف بحقولها وبانيها ودوالها
- إنشاء الكائنات واستخدامها
- فهم المراجع مقابل القيم
- استخدام الكلمة المفتاحية
staticبشكل مناسب
الأجزاء 7-9: مفاهيم متقدمة
- التمييز بين التغيير وإعادة الإسناد
- استخدام الكلمة المفتاحية
finalبشكل صحيح - العمل مع القوائم (Lists) والمجموعات (Sets) والخرائط (Maps)
- اختيار نوع المجموعة المناسب
المشاريع
- إتمام نظام إدارة الطلاب
- الاختبار الشامل بما في ذلك الحالات الحدّية (Edge Cases)
- تطبيق أسلوب برمجة جيد
📝 تكليف: نظام مكتبة
أنشئ صنفَي Book وLibrary بحيث:
- يمكن استعارة الكتب (Checked out) وإعادتها
- تتتبّع المكتبة جميع الكتب
- تعرض المكتبة الكتب المتاحة
المتطلبات:
- صنف
Bookيحتوي على العنوان، والمؤلف، وحالة الاستعارة - صنف
Libraryيحتوي على مجموعة من الكتب - دوال لإضافة الكتب واستعارتها وإعادتها
- معالجة صحيحة للأخطاء
برمجة سعيدة! 🎉
جامعة المنصورة
- الفصل الدراسي الأول - 2020-2021
- قسم علوم الحاسب
- كلية الحاسبات والمعلومات
- [CS ---] بناء البرمجيات
- الفرقة: 4
- المعمل: 2
- د. عمر الزكي
- عبد الرحمن جمال
جدول المحاضرة
- مقدمة في جافا
- الأنواع، المتغيرات، العوامل (Operators)
- الدوال، الشروط
- الحلقات، المصفوفات
- الأصناف، الكائنات
- 2
جدول المحاضرة
- القيم البدائية (Primitive values)
- القيم الكائنية (Object values)
- تغيير محتوى القيم مقابل إعادة إسناد المتغيرات
- إعادة الإسناد والقيم الثابتة
- القيم القابلة للتغيير (Mutable)
- المراجع الثابتة (Immutable references)
- مجموعات جافا (Java Collections)
- 3
القيم البدائية، القيم الكائنية
- تُمثَّل القيم البدائية (Primitive values) بثوابت مجردة. السهم الوارد هو مرجع (Reference) إلى القيمة من متغير أو من حقل كائن.
- القيمة الكائنية (Object value) هي دائرة تحمل اسم نوعها. عندما نريد إظهار مزيد من التفاصيل، نكتب أسماء الحقول داخلها، مع أسهم تشير إلى قيمها. ولمزيد من التفصيل، يمكن أن تتضمن الحقول أنواعها المُعرَّفة. يفضّل بعض الأشخاص كتابة x:int بدلاً من int x، وكلاهما صحيح.
- 4
القيم البدائية، القيم الكائنية
- 5
تغيير محتوى القيم مقابل إعادة إسناد المتغيرات
- عندما تُسند قيمة إلى متغير أو حقل، فأنت تغيّر الجهة التي يشير إليها سهم المتغير. يمكنك توجيهه نحو قيمة مختلفة.
- عندما تُسند قيمة إلى محتوى قيمة قابلة للتغيير - مثل مصفوفة أو قائمة - فأنت تغيّر المراجع داخل تلك القيمة.
- 6
إعادة الإسناد والقيم الثابتة
- 7
القيم القابلة للتغيير (Mutable values)
- 8
المراجع الثابتة (Immutable references)
- تمنحنا جافا أيضًا مراجع ثابتة (Immutable references): متغيرات تُسنَد لها قيمة مرة واحدة ولا يُعاد إسنادها أبدًا. لجعل المرجع ثابتًا، عرّفه باستخدام الكلمة المفتاحية final:
- Final int num;
- في مخطط اللقطة (Snapshot diagram)، يُشار إلى المرجع الثابت (final) بسهم مزدوج. إليك كائنًا لا يتغيّر معرّفه (id) أبدًا (لا يمكن إعادة إسناده إلى رقم مختلف)، لكن يمكن أن يتغيّر عمره (age).
- 9
القوائم، المجموعات، والخرائط (Lists, Sets, and Maps)
- 10
- تحتوي القائمة (List) على مجموعة مرتّبة من صفر أو أكثر من الكائنات، حيث يمكن أن يظهر نفس الكائن أكثر من مرة. يمكننا إضافة عناصر إلى القائمة (List) وإزالتها منها، وستكبر
- وتصغر لتستوعب محتوياتها
القائمة (List)
- 11
القائمة (List)
- 12
المجموعات (Sets)
- 13
المجموعات (Sets)
- 14
الخريطة (Map)
- 15
الخريطة (Map)
- 16
استخدامات الخريطة (مثال)
- خريطة من أكواد الأخطاء ووصفها.
- خريطة من الرموز البريدية والمدن.
- خريطة من المديرين والموظفين. كل مدير (مفتاح) مرتبط بقائمة من الموظفين (قيمة) الذين يديرهم.
- خريطة من الفصول والطلاب. كل فصل (مفتاح) مرتبط بقائمة من الطلاب (قيمة).
- 17