CodeGym /وبلاگ جاوا /Random-FA /مقادیر ثابت در جاوا: نهایی، ثابت و تغییرناپذیر
John Squirrels
مرحله
San Francisco

مقادیر ثابت در جاوا: نهایی، ثابت و تغییرناپذیر

در گروه منتشر شد
سلام! شما قبلاً با کلمه "تغییر کننده" آشنا هستید. حداقل، شما با اصلاح کننده های دسترسی (عمومی، خصوصی) و اصلاح کننده ایستا مواجه شده اید. امروز ما یک اصلاح کننده خاص به نام final را مورد بحث قرار خواهیم داد . می توانید بگویید اصلاح کننده نهایی بخش هایی از برنامه ما را که در آن رفتارهای ثابت، بدون ابهام و تغییرناپذیر مورد نیاز است، "سیمان" می کند. سه مکان در برنامه های شما وجود دارد که می توانید از آن استفاده کنید: کلاس ها، متدها و متغیرها. مقادیر ثابت در جاوا: نهایی، ثابت و غیر قابل تغییر - 2 بیایید به ترتیب آنها را مرور کنیم. اگر اصلاح کننده نهایی در یک اعلان کلاس استفاده شود، به این معنی است که کلاس نمی تواند ارث بری شود. در درس های قبلی از یک مثال ساده ارثی استفاده کردیم: یک کلاس والدین و دو کلاس فرزند داشتیم Animal: CatوDog
public class Animal {
}



public class Cat extends Animal {
   // Fields and methods of the Cat class
}


public class Dog extends Animal {

   // Fields and methods of the Dog class
}
با این حال، اگر از اصلاح کننده نهایی در کلاس استفاده کنیم Animal، کلاس های Catand Dogنمی توانند آن را به ارث ببرند.
public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
کامپایلر بلافاصله یک خطا ایجاد می کند. در جاوا، بسیاری از کلاس های نهایی در حال حاضر پیاده سازی شده اند. در میان مواردی که اغلب استفاده می کنید، Stringشناخته شده ترین آنهاست. علاوه بر این، اگر یک کلاس به عنوان نهایی اعلام شود ، تمام متدهای کلاس نیز نهایی می شوند . معنی آن چیست؟ اگر روشی با استفاده از اصلاح کننده نهایی اعلام شده باشد ، نمی توانید آن متد را لغو کنید. به عنوان مثال، در اینجا ما یک Animalکلاس داریم که یک speak()متد را اعلام می کند. اما، سگ ها و گربه ها قطعا به روش های مختلف "صحبت می کنند". Catبنابراین، متدهای speak() را در هر دو کلاس و اعلام می‌کنیم Dog، اما آنها را متفاوت پیاده‌سازی می‌کنیم.
public class Animal {

   public void speak() {
       System.out.println("Hello!");
   }
}

public class Cat extends Animal {

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

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}
ما کلاس‌های Catand Dogرا روی متد اعلام‌شده در کلاس والد نادیده گرفتیم. حال، یک حیوان بسته به نوع جسم آن، متفاوت صحبت می کند:
public class Main {

   public static void main(String[] args) {

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

       cat.speak();
       dog.speak();
   }
}
خروجی: میو! ووف Animalبا این حال، اگر متد کلاس را نهایی اعلام کنیم speak()، نمی‌توانیم آن را در کلاس‌های دیگر لغو کنیم:
public class Animal {

   public final void speak() {
       System.out.println("Hello!");
   }
}


public class Cat extends Animal {

   @Override
   public void speak() {// Error! A final method can't be overridden!
       System.out.println("Meow!");
   }
}
و اشیاء ما مجبور خواهند شد از speak()متدی که در کلاس والد تعریف شده است استفاده کنند:
public static void main(String[] args) {

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

   cat.speak();
   dog.speak();
}
خروجی: سلام! سلام! حال در مورد متغیرهای نهایی . آنها همچنین به عنوان ثابت شناخته می شوند . اول (و مهمتر از همه)، مقدار اولیه اختصاص داده شده به یک مقدار ثابت را نمی توان تغییر داد. یک بار برای همیشه تعیین می شود.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;// Error! You can't assign a new value to a final variable!
   }
}
یک ثابت نیازی به مقداردهی اولیه ندارد. که بعداً قابل انجام است. اما، مقداری که در ابتدا به آن اختصاص داده شده است، برای همیشه ثابت می ماند.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
دوم، به نام متغیر ما توجه کنید. جاوا یک قرارداد نامگذاری متفاوت برای ثابت ها دارد. این نماد معمولی camelCase نیست . اگر یک متغیر معمولی بود، آن را ثابتExample می نامیدیم . اما، نام ثابت‌ها با حروف بزرگ نوشته می‌شوند، با زیرخط بین کلمات (اگر بیش از یک کلمه وجود داشته باشد)، به عنوان مثال "CONSTANT_EXAMPLE". چرا به ثابت نیاز داریم؟ برای مثال اگر مقدار ثابتی وجود داشته باشد که به طور مرتب در یک برنامه استفاده می کنید، بسیار مفید هستند. به عنوان مثال، شما تصمیم گرفته اید تاریخ سازی کنید و بازی "The Witcher 4" را خودتان بنویسید. بدیهی است که بازی به طور مرتب از نام قهرمان داستان استفاده می کند: "Geralt of Rivia". این رشته (و نام قهرمانان دیگر) بهتر است به عنوان یک ثابت اعلان شود: مقدار آن در یک مکان ذخیره می شود و قطعاً هنگام وارد کردن یک میلیون بار اشتباه تایپی نخواهید داشت.
public class TheWitcher4 {

   private static final String GERALT_NAME = "Geralt of Rivia";
   private static final String YENNEFER_NAME = "Yennefer of Wengerberg";
   private static final String TRISS_NAME = "Triss Merigold";

   public static void main(String[] args) {

       System.out.println("The Witcher 4");
       System.out.println("It's already the fourth Witcher game, but " + GERALT_NAME + " still can't decide who" +
               " he likes more: " + YENNEFER_NAME + " or " + TRISS_NAME);

       System.out.println("But, if you've never played The Witcher before, we'll start from the beginning.");
       System.out.println("The protagonist's name is " + GERALT_NAME);
       System.out.println(GERALT_NAME + " is a witcher, a monster hunter");
   }
}
خروجی: The Witcher 4 در حال حاضر چهارمین بازی Witcher است، اما گرالت از ریویا هنوز نمی تواند تصمیم بگیرد که چه کسی را بیشتر دوست دارد: Yennefer از Wengerberg یا Triss Merigold اما، اگر قبلاً The Witcher را بازی نکرده اید، ما از این بازی شروع می کنیم. شروع نام قهرمان داستان Geralt of Rivia است Geralt of Rivia یک جادوگر، یک شکارچی هیولا است . اکنون قطعاً اشتباه تایپی نخواهیم کرد و نیازی نیست که هر بار آنها را با دست بنویسیم. مزیت دیگر: اگر زمانی نیاز به تغییر مقدار متغیر در کل برنامه داشتیم، می‌توانید این کار را در یک مکان انجام دهید، نه اینکه به صورت دستی آن را در کل پایه کد تغییر دهید. :)

انواع تغییرناپذیر

همانطور که با جاوا کار کرده اید، احتمالاً قبلاً به این ایده عادت کرده اید که برنامه نویسان تقریباً کنترل کاملی بر وضعیت همه اشیا دارند. اگر می خواهید یک Catشی ایجاد کنید، می توانید. اگر می خواهید نام آن را تغییر دهید، می توانید. اگر می خواهید سن آن یا چیز دیگری را تغییر دهید، می توانید. اما جاوا دارای چندین نوع داده است که دارای خاصیت خاصی هستند. تغییر ناپذیرند . اگر یک کلاس تغییرناپذیر باشد، نمی توان وضعیت اشیاء آن را تغییر داد. چند نمونه می خواهید؟ ممکن است شما را شگفت زده کند، اما شناخته شده ترین کلاس تغییرناپذیر String است! بنابراین، ما واقعا نمی توانیم مقدار یک رشته را تغییر دهیم؟ خوب، بیایید آن را امتحان کنیم:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1 = "I love Python";// but changing str1 has no impact on str2
   System.out.println(str2);// str2 continues to point to the "I love Java" string, but str1 now points to a different object
}
خروجی: I love Java I love Java After we write
str1 = "I love Python";
شی "I love Java"رشته تغییر نکرد یا به جایی نرفت. هنوز هم خوشبختانه وجود دارد و دقیقاً همان متن قبلی را دارد. کد
str1 = "I love Python";
به سادگی یک شی دیگر ایجاد کرد که str1 اکنون به آن اشاره می کند. اما، به نظر نمی‌رسد که هیچ تأثیری روی شی رشته «I love Java» داشته باشیم. خوب، بیایید چیز دیگری را امتحان کنیم! کلاس Stringپر از متدها است و برخی از آنها به نظر می رسد که وضعیت شی را تغییر می دهند! به عنوان مثال، یک روش وجود دارد replace(). بیایید کلمه "جاوا" را به "پایتون" در رشته خود تغییر دهیم!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1.replace("Java", "Python");// We try to change the state of str1 by swapping the word "Java" with "Python"
   System.out.println(str2);
}
خروجی: I love Java I love Java دوباره کار نکرد! شاید روش جایگزینی جواب ندهد؟ بیایید چیز دیگری را امتحان کنیم. مثلا، substring(). یک زیررشته بر اساس شاخص های کاراکتر ارسال شده به عنوان آرگومان برمی گرداند. بیایید 10 کاراکتر اول رشته خود را قطع کنیم:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1.substring(10);// Truncate the original String
   System.out.println(str2);
}
خروجی: من عاشق جاوا هستم من عاشق جاوا هستم مقادیر ثابت در جاوا: نهایی، ثابت و غیرقابل تغییر - 3 هیچ چیز تغییر نکرده است. و نباید داشته باشد. همانطور که قبلاً گفتیم، رشته ها تغییر ناپذیر هستند. بنابراین، همه متدهای کلاس چیست String؟ پس از همه، آنها می توانند رشته ها را کوتاه کنند، کاراکترها را تغییر دهند و موارد دیگر. اگر هیچ اتفاقی نیفتد چه فایده ای دارد؟ آنها در واقع می توانند این کارها را انجام دهند! اما، آنها هر بار یک رشته جدید را برمی گردانند. نوشتن بی معنی است
str1.replace("Java", "Python");
زیرا نمی توانید شی اصلی را تغییر دهید. اما، اگر نتیجه روش را روی یک متغیر مرجع جدید بنویسید، بلافاصله تفاوت را خواهید دید!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

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

   System.out.println(str1AfterReplacement);
}
همه Stringروش ها به این صورت عمل می کنند. هیچ کاری نمی توان با شی انجام داد "I love Java". شما فقط می توانید یک شی جدید ایجاد کنید و بنویسید: "<new object> = نتیجه دستکاری در "I love Java" object ". چه انواع دیگری غیرقابل تغییر هستند؟ برخی از آنها را که قطعاً باید فوراً به خاطر بسپارید، همه کلاس های wrapper برای انواع اولیه هستند Integer. Byte, Character, Short, Boolean, Long, Double, Float: همه این کلاس ها immutableاشیاء ایجاد می کنند (در درس های آینده در مورد آنها صحبت خواهیم کرد). این شامل کلاس هایی است که برای ایجاد اعداد بزرگ مانند BigIntegerو استفاده می شود BigDecimal. ما اخیراً استثناها را پوشش دادیم و ردیابی پشته را لمس کردیم . حدس بزنید، اشیاء java.lang.StackTraceElement نیز تغییرناپذیر هستند. این منطقی است: اگر کسی بتواند داده‌های پشته ما را تغییر دهد، همه چیز بی‌معنی می‌شود. تصور کنید کسی از ردیابی پشته عبور می‌کند و OutOfMemoryError را به FileNotFoundException تغییر می‌دهد . و سپس شما از آن پشته برای پیدا کردن علت خطا استفاده می کنید. اما برنامه حتی از فایل ها استفاده نمی کند. :) بنابراین، آنها این اشیاء را غیرقابل تغییر کردند، فقط برای هر موردی. بسیار خوب، پس کم و بیش برای StackTraceElement منطقی است . ، چرا کسی باید رشته ها را تغییرناپذیر کند؟ چرا تغییر ارزش های آنها مشکل ساز است؟ احتمالاً حتی راحت تر خواهد بود. :/ دلایل مختلفی برای این وجود دارد. اول اینکه حافظه را ذخیره می کند. رشته‌های تغییرناپذیر را می‌توان در مجموعه رشته‌ها قرار داد و به جای ایجاد رشته‌های جدید امکان استفاده مجدد از رشته‌ها را می‌دهد. دوم، برای امنیت. به عنوان مثال، نام کاربری و رمز عبور تقریباً در هر برنامه ای رشته هستند. ایجاد امکان تغییر آنها می تواند منجر به مشکلات مجوز شود. دلایل دیگری نیز وجود دارد، اما مطالعه ما درباره جاوا هنوز آنها را پوشش نداده است، بنابراین بعداً به آنها خواهیم پرداخت.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION