JavaRush /مدونة جافا /Random-AR /النهائية والثوابت وغير القابلة للتغيير في جافا

النهائية والثوابت وغير القابلة للتغيير في جافا

نشرت في المجموعة
مرحبًا! كلمة "المعدل" مألوفة لك بالفعل. على الأقل، صادفت معدّلات الوصول (العامة والخاصة) والمعدّل الثابت. سنتحدث اليوم عن المعدل النهائي الخاص . يمكن القول إنه "يرسخ" تلك المجالات في برنامجنا حيث نحتاج إلى سلوك ثابت لا لبس فيه وغير متغير. يمكن استخدامه في ثلاثة مجالات في برنامجنا: الفئات والأساليب والمتغيرات. غير قابل للتغيير في جافا: نهائي، ثوابت وغير قابل للتغيير - 2 دعونا نذهب من خلالهم واحدا تلو الآخر. إذا كان إعلان الفئة يحتوي على المعدل النهائي ، فهذا يعني أنه لا يمكنك أن ترث من هذه الفئة. في المحاضرات السابقة، رأينا مثالاً بسيطًا على الوراثة: كان لدينا صنف الوالدين Animal، وصنفين تابعين - CatوDog
public class Animal {
}

public class Cat extends Animal {
   //..поля и методы класса Cat
}

public class Dog extends Animal {

   //..поля и методы класса Dog
}
ومع ذلك، إذا قمنا بتحديد Animalمُعدِّل لفئة ما final، فلن تتمكن الفئات من وراثة منه Catأيضًا Dog.
public final class Animal {

}

public class Cat extends Animal {

   //ошибка! Cannot inherit from final Animal
}
المترجم ينتج خطأ على الفور. هناك العديد من الفئات المطبقة بالفعل في Java final. وأشهر تلك التي تستخدمها باستمرار هو String. بالإضافة إلى ذلك، إذا تم الإعلان عن فئة كـ final، فإن جميع أساليبها تصبح أيضًا final. ماذا يعني ذلك؟ إذا تم تحديد معدّل لطريقة ما final، فلا يمكن تجاوز هذه الطريقة. على سبيل المثال، لدينا فئة Animalتحدد الطريقة voice(). ومع ذلك، فمن الواضح أن الكلاب والقطط "تتحدث" بشكل مختلف. لذلك، في كل فئة - Catو Dog- سنقوم بإنشاء طريقة voice()، لكننا سننفذها بشكل مختلف.
public class Animal {

   public void voice() {
       System.out.println("Voice!");
   }
}

public class Cat extends Animal {

   @Override
   public void voice() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void voice() {
       System.out.println("Woof!");
   }
}
في الفصول الدراسية Catوقمنا Dogبتجاوز طريقة الفصل الأصلي. الآن سينطق الحيوان اعتمادًا على نوع الكائن الذي ينتمي إليه:
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       Dog dog = new Dog();

       cat.voice();
       dog.voice();
   }
}
الخلاصة: مواء! اللحمة! ومع ذلك، إذا Animalأعلنا عن طريقة في فئة voice()مثل final، فلن يكون من الممكن إعادة تعريفها في فئات أخرى:
public class Animal {

   public final void voice() {
       System.out.println("Voice!");
   }
}


public class Cat extends Animal {

   @Override
   public void voice() {//ошибка! final-метод не может быть переопределен!
       System.out.println("Meow!");
   }
}
بعد ذلك سيتم إجبار كائناتنا على استخدام الطريقة voice()كما هي محددة في الفئة الأصل:
public static void main(String[] args) {

   Cat cat = new Cat();
   Dog dog = new Dog();

   cat.voice();
   dog.voice();
}
الخلاصة: صوت! صوت! الآن عن final-المتغيرات. وإلا فإنها تسمى ثوابت . أولاً (والأهم من ذلك)، لا يمكن تغيير القيمة الأولى المخصصة للثابت. يتم تعيينه مرة واحدة وإلى الأبد.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;//ошибка! Нельзя присвоить новое meaning final-переменной!
   }
}
لا يحتاج الثابت إلى التهيئة على الفور. يمكن القيام بذلك لاحقًا. لكن القيمة المخصصة أولاً ستبقى إلى الأبد.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;//так делать можно
}
ثانيًا، انتبه إلى اسم المتغير الخاص بنا. ثوابت Java لها اصطلاح تسمية مختلف. هذه ليست حالة الجمل التي اعتدنا عليها. في حالة وجود متغير عادي، فإننا نسميه ConstantExample، ولكن أسماء الثوابت مكتوبة بأحرف كبيرة، وبين الكلمات (إذا كان هناك العديد منها) توجد شرطة سفلية - "CONSTANT_EXAMPLE". لماذا هناك حاجة إلى الثوابت؟ على سبيل المثال، ستكون مفيدة إذا كنت تستخدم باستمرار بعض القيم الثابتة في البرنامج. لنفترض أنك قررت أن تدخل التاريخ وتكتب لعبة "The Witcher 4" بمفردك. من الواضح أن اللعبة ستستخدم باستمرار اسم الشخصية الرئيسية - "Geralt of Rivia". من الأفضل فصل هذا السطر وأسماء الأبطال الآخرين إلى ثابت: القيمة التي تحتاجها سيتم تخزينها في مكان واحد، وبالتأكيد لن تخطئ عند كتابتها للمرة المليون.
public class TheWitcher4 {

   private static final String GERALT_NAME = "Геральт из Ривии";
   private static final String YENNEFER_NAME = "Йеннифэр из Венгерберга";
   private static final String TRISS_NAME = "Трисс Меригольд";

   public static void main(String[] args) {

       System.out.println("Ведьмак 4");
       System.out.println("Это уже четвертая часть Ведьмака, а " + GERALT_NAME + " ниHow не определится кто ему" +
               " нравится больше: " + YENNEFER_NAME + " or " + TRISS_NAME);

       System.out.println("Но если вы никогда не играли в Ведьмака - начнем сначала.");
       System.out.println("Главного героя зовут " + GERALT_NAME);
       System.out.println(GERALT_NAME + " - ведьмак, охотник на чудовищ");
   }
}
خاتمة:
Ведьмак 4
Это уже четвертая часть Ведьмака, а Геральт из Ривии ниHow не определится, кто ему нравится больше: Йеннифэр из Венгерберга or Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
لقد قمنا بفصل أسماء الشخصيات إلى ثوابت، والآن بالتأكيد لن نخطئ في إملائها، ولن تكون هناك حاجة لكتابتها يدويًا في كل مرة. ميزة أخرى: إذا أردنا في النهاية تغيير قيمة متغير عبر البرنامج، فيكفي القيام بذلك في مكان واحد، بدلاً من إعادته يدويًا عبر الكود بأكمله :)

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

خلال فترة عملك في Java، ربما تكون معتادًا بالفعل على حقيقة أن المبرمج يتحكم بشكل كامل تقريبًا في حالة جميع الكائنات. مطلوب - إنشاء كائن Cat. إذا أردت ذلك، قمت بإعادة تسميته. إذا أراد غير عمره أو أي شيء آخر. ولكن في Java يوجد العديد من أنواع البيانات التي لها حالة خاصة. فهي غير قابلة للتغيير ، أو غير قابلة للتغيير . هذا يعني أنه إذا كانت الفئة غير قابلة للتغيير، فلا يمكن تغيير حالة كائناتها. أمثلة؟ قد تتفاجأ، لكن المثال الأكثر شهرة للفئة غير القابلة للتغيير هو String! يبدو أننا لا نستطيع تغيير قيمة السلسلة؟ دعونا نحاول:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1 = "I love Python";//но поведение str1 ниHow не влияет на str2
   System.out.println(str2);//str2 продолжает указывать на строку "I love Java", хотя str1 уже указывает на другой an object
}
الخلاصة: أنا أحب جافا أحب جافا بعد أن كتبنا:
str1 = "I love Python";
الكائن الذي يحتوي على السلسلة "I love Java" لم يتغير ولم يذهب إلى أي مكان. إنه موجود بأمان ويحتوي على نفس النص تمامًا كما كان من قبل. شفرة:
str1 = "I love Python";
لقد قمت للتو بإنشاء كائن آخر والآن str1يشير المتغير إليه. لكن لا يمكننا التأثير على كائن "أنا أحب Java" بأي شكل من الأشكال. حسنا، دعونا نحاول بشكل مختلف! الفصل Stringمليء بالأساليب، ويبدو أن بعضها يغير حالة الصف! على سبيل المثال، هناك طريقة replace(). دعونا نغير كلمة "Java" إلى كلمة "Python" في خطنا!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1.replace("Java", "Python");//попробуем изменить состояние str1, заменив слово "Java" на “Python”
   System.out.println(str2);
}
الخلاصة: أنا أحب جافا، أحب جافا، ولم ينجح الأمر مرة أخرى! ربما طريقة المنحنى لا تعمل؟ دعونا نجرب واحدة أخرى. على سبيل المثال، substring(). يقوم بقص سلسلة بناءً على أرقام الأحرف المرسلة. دعنا نختصر الأحرف العشرة الأولى:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1.substring(10);//обрезаем исходную строку
   System.out.println(str2);
}
الخلاصة: أنا أحب جافا، أحب جافا غير قابل للتغيير في جافا: نهائي، ثوابت وغير قابل للتغيير - 3 لم يتغير شيء. ولا ينبغي أن يكون. كما قلنا، الأشياء Stringغير قابلة للتغيير. فما هي إذن كل هذه الأساليب الطبقية String؟ يمكنهم قطع الخط وتغيير الأحرف فيه وما إلى ذلك. لماذا يحتاجون إذا لم يحدث شيء؟ يستطيعون! لكنهم يعيدون كائن سلسلة جديدًا في كل مرة. لا فائدة من الكتابة:
str1.replace("Java", "Python");
- لن تقوم بتغيير الكائن الأصلي. ولكن إذا قمت بكتابة نتيجة الطريقة في متغير مرجعي جديد، فسوف ترى الفرق على الفور!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   String str1AfterReplacement =  str1.replace("Java", "Python");
   System.out.println(str2);

   System.out.println(str1AfterReplacement);
}
هذه هي الطريقة الوحيدة Stringالتي تعمل بها كل هذه الأساليب. لا يمكنك فعل أي شيء باستخدام كائن "أنا أحب Java" . ما عليك سوى إنشاء كائن جديد وكتابة: "كائن جديد = نتيجة بعض المعالجات باستخدام كائن "أنا أحب Java" ." ما هي الأنواع الأخرى غير القابلة للتغيير؟ مما تحتاج بالتأكيد إلى تذكره الآن - جميع فئات الغلاف على الأنواع البدائية غير قابلة للتغيير. Integer, Byte, Character, Short, Boolean, Long, Double- Floatكل هذه الفئات تنشئ كائنات غير قابلة للتغيير . يتضمن هذا أيضًا الفئات المستخدمة لإنشاء أعداد كبيرة - BigIntegerو BigDecimal. لقد مررنا مؤخرًا بالاستثناءات وتطرقنا إليها StackTrace. لذلك: كائنات فئة java.lang.StackTraceElement غير قابلة للتغيير أيضًا. هذا أمر منطقي: إذا تمكن شخص ما من تغيير البيانات الموجودة على مكدسنا، فيمكنه إلغاء كل العمل بها. تخيل أن شخصًا ما انتقل إلى StackTrace وقام بتغيير OutOfMemoryError إلى FileNotFoundException . ويجب عليك العمل مع هذا المكدس والبحث عن سبب الخطأ. والبرنامج لا يستخدم الملفات على الإطلاق :) لذلك، لكي تكون في الجانب الآمن، تم جعل هذه الكائنات غير قابلة للتغيير. حسنًا، مع StackTraceElement يكون الأمر أكثر أو أقل وضوحًا. لماذا يريد أي شخص أن يجعل السلاسل غير قابلة للتغيير؟ ماذا ستكون المشكلة لو كان من الممكن تغيير قيمها. ربما يكون الأمر أكثر ملاءمة :/ هناك عدة أسباب لذلك. أولاً، حفظ الذاكرة. يمكن وضع سلاسل ثابتة String Poolويمكن استخدام نفس السلاسل في كل مرة بدلاً من إنشاء سلاسل جديدة. ثانيا، السلامة. على سبيل المثال، معظم عمليات تسجيل الدخول وكلمات المرور في أي برنامج عبارة عن سلاسل. قد تؤدي إمكانية تغييرها إلى مشاكل في الترخيص. هناك أسباب أخرى، لكننا لم نصل إليها بعد في تعلم Java، سنعود إليها لاحقًا.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION