الفئات المحلية والمجهولة
صرّح بفئات داخل الأساليب وأنشئ تطبيقات مجهولة للواجهات عند الحاجة
الفئات المحلية والمجهولة درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.
الفئات المحلية والمجهولة
تُعرَّف الفئات المحلية داخل أسلوب. أما الفئات المجهولة فهي فئات محلية بلا اسم — إذ تجمع بين تعريف الفئة وإنشاء مثيل منها. تلتقط كلتاهما المتغيرات المحلية النهائية فعليًا.
تصريح الفئة المحلية
يُصرَّح عن الفئة المحلية داخل جسم أسلوب. ويمكنها الوصول إلى أعضاء الفئة المحتوية والمتغيرات المحلية النهائية فعليًا.
static void greet(String language) {
// Local class — defined inside the method
class Greeter {
String sayHello(String name) {
// Can access 'language' — it is effectively final
return switch (language) {
case "EN" -> "Hello, " + name;
case "ES" -> "Hola, " + name;
case "FR" -> "Bonjour, " + name;
default -> "Hi, " + name;
};
}
}
Greeter g = new Greeter();
System.out.println(g.sayHello("Alice"));
}
greet("ES"); // Hola, Aliceالمتغيرات النهائية فعليًا
لا يمكن للفئات المحلية والمجهولة التقاط المتغيرات المحلية إلا إذا كانت نهائية فعليًا — أي لم يُعَد إسناد قيمة إليها بعد تهيئتها.
void process(int threshold) {
// threshold is effectively final (never reassigned)
Runnable r = new Runnable() {
public void run() {
System.out.println("Threshold: " + threshold);
}
};
r.run();
// threshold = 10; // If you add this, the anonymous class won't compile
}أساسيات الفئات المجهولة
تطبّق الفئة المجهولة واجهة أو تمدّد فئة مباشرةً، وذلك ضمن تعبير واحد.
interface Comparator<T> {
int compare(T a, T b);
}
// Anonymous class implementing Comparator
java.util.Comparator<String> byLength = new java.util.Comparator<String>() {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
};
List<String> words = new ArrayList<>(List.of("banana", "fig", "apple", "kiwi"));
words.sort(byLength);
System.out.println(words); // [fig, kiwi, apple, banana]الفئة المجهولة مقابل Lambda
بالنسبة إلى الواجهات ذات الأسلوب المجرّد الواحد (SAM)، تحل تعبيرات Lambda محل الفئات المجهولة. ومع ذلك، تظل الفئات المجهولة ضرورية للواجهات التي تحتوي على عدة أساليب أو عند تمديد الفئات المجرّدة.
// Anonymous class for single-method interface
Runnable r1 = new Runnable() {
public void run() { System.out.println("Running!"); }
};
// Lambda — cleaner for SAM interfaces
Runnable r2 = () -> System.out.println("Running!");
// Must use anonymous class for multi-method interface:
java.io.FilenameFilter filter = new java.io.FilenameFilter() {
public boolean accept(java.io.File dir, String name) {
return name.endsWith(".java");
}
}; // FilenameFilter is not a SAM — no lambda shorthandالفئة المجهولة ذات الحالة
يمكن للفئات المجهولة أن تحتوي على حقول، بخلاف تعبيرات Lambda. ويكون ذلك مفيدًا عند الحاجة إلى الاحتفاظ بحالة داخل التطبيق المجهول.
interface Counter { int increment(); int get(); }
Counter counter = new Counter() {
private int count = 0;
public int increment() { return ++count; }
public int get() { return count; }
};
System.out.println(counter.increment()); // 1
System.out.println(counter.increment()); // 2
System.out.println(counter.get()); // 2نمط المستمع المجهول
قبل ظهور تعبيرات Lambda، كانت الفئات المجهولة هي النمط القياسي لمستمعات الأحداث في برمجة واجهات المستخدم الرسومية وAndroid.
// Modern Android/Swing style: anonymous class listener
Button loginButton = new Button(); // hypothetical
loginButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick() {
System.out.println("Login button clicked!");
}
});
// Modern equivalent with lambda (if OnClickListener is SAM):
loginButton.setOnClickListener(() -> System.out.println("Clicked!"));الفئة المحلية للمنطق المعقّد
تكون الفئات المحلية مناسبة عندما تحتاج إلى فئة تحتوي على عدة أساليب في موضع واحد فقط — فهي معقّدة أكثر من أن تكون تعبير Lambda، ومحددة أكثر من أن تكون فئة من المستوى الأعلى.
static List<String> processData(List<String> data, String prefix) {
// Local class: complex enough for a class, used only here
class DataProcessor {
List<String> result = new ArrayList<>();
void process(String item) {
// prefix is effectively final
if (item.startsWith(prefix)) {
result.add(item.toUpperCase());
}
}
}
DataProcessor dp = new DataProcessor();
data.forEach(dp::process);
return dp.result;
}
System.out.println(processData(List.of("apple","avocado","banana"), "a"));
// [APPLE, AVOCADO]الفئة المجهولة للفئة المجرّدة
يمكن للفئات المجهولة تمديد الفئات المجرّدة، مع تجاوز الأساليب المجرّدة دون إنشاء فئة فرعية مسماة.
abstract class ReportFormatter {
abstract String formatHeader(String title);
abstract String formatBody(List<String> rows);
String format(String title, List<String> rows) {
return formatHeader(title) + "\n" + formatBody(rows);
}
}
ReportFormatter csvFormatter = new ReportFormatter() {
public String formatHeader(String t) { return "\"" + t + "\""; }
public String formatBody(List<String> rows) {
return String.join("\n", rows);
}
};
System.out.println(csvFormatter.format("Sales", List.of("a,1","b,2")));النمط المضاد للتهيئة ذات القوسين المعقوفين
تستخدم حيلة التهيئة ذات القوسين المعقوفين الفئات المجهولة لتهيئة المجموعات. وهي تنشئ فئة فرعية تحتوي على مهيّئ مثيل. تجنّبها — فهي غير فعّالة ومعرّضة للأخطاء.
// Anti-pattern: double-brace initialization
Map<String, Integer> map = new HashMap<String, Integer>() {{
put("a", 1);
put("b", 2);
}};
// Creates an anonymous HashMap subclass — wasteful!
// GOOD: use Map.of() or Map.ofEntries()
Map<String, Integer> better = Map.of("a", 1, "b", 2);
// Or a mutable map:
Map<String, Integer> mutable = new HashMap<>(Map.of("a", 1, "b", 2));الاختيار: Lambda أم فئة مجهولة أم فئة محلية
دليل اتخاذ القرار:
- Lambda: أسلوب مجرّد واحد، دون حالة إضافية أو توريث
- الفئة المجهولة: عدة أساليب، أو الحاجة إلى حالة، أو تمديد فئة مجرّدة
- الفئة المحلية: الحاجة إلى إعادة الاستخدام داخل الأسلوب، مع عدة أساليب وحالة معقّدة
تحقق سريع
ما الذي تفعله الفئة المجهولة دائمًا ضمن تعبير واحد؟
مراجعة: الفئات المحلية والمجهولة
أهم النقاط:
- تُعرَّف الفئات المحلية داخل الأساليب، ويمكنها الوصول إلى المتغيرات المحلية النهائية فعليًا
- تجمع الفئات المجهولة بين تعريف الفئة وإنشاء مثيل منها ضمن تعبير واحد
- يمكن للفئات المجهولة أن تحتوي على حقول وعدة أساليب — بخلاف تعبيرات Lambda
- تحل تعبيرات Lambda محل الفئات المجهولة في الواجهات ذات الأسلوب المجرّد الواحد
- استخدم الفئات المحلية عندما يكون المنطق معقّدًا بما يكفي لفئة، لكنه خاص بأسلوب واحد
- تجنّب التهيئة ذات القوسين المعقوفين — فهي تنشئ فئات فرعية مجهولة غير ضرورية
الأسئلة الشائعة
هل درس «الفئات المحلية والمجهولة» مجاني؟
نعم — نص درس «الفئات المحلية والمجهولة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.
ماذا ستتعلم في «الفئات المحلية والمجهولة»؟
صرّح بفئات داخل الأساليب وأنشئ تطبيقات مجهولة للواجهات عند الحاجة تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟
لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «الفئات المحلية والمجهولة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟
نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- الفئات المتداخلة الثابتة
- الفئات الداخلية والوصول إلى الفئة الخارجية
- الفئات المحلية والمجهولة
- اختيار استراتيجية التداخل المناسبة