ہیلو! لفظ "موڈیفائر" آپ کے لیے پہلے سے ہی واقف ہے۔ کم از کم، آپ کو رسائی میں ترمیم کرنے والے (عوامی، نجی) اور جامد ترمیم کار کا سامنا کرنا پڑا ہے۔ آج ہم اسپیشل فائنل موڈیفائر کے بارے میں بات کریں گے ۔ اسے ہمارے پروگرام کے ان شعبوں کو "سیمنٹ" کرنے کے لیے کہا جا سکتا ہے جہاں ہمیں مستقل، غیر مبہم، غیر تبدیل شدہ رویے کی ضرورت ہے۔ اسے ہمارے پروگرام کے تین شعبوں میں استعمال کیا جا سکتا ہے: کلاسز، طریقے اور متغیر۔ آئیے ایک ایک کرکے ان کے ذریعے چلتے ہیں۔ اگر کسی کلاس ڈیکلریشن میں فائنل موڈیفائر ہوتا ہے تو اس کا مطلب ہے کہ آپ اس کلاس سے وراثت نہیں پا سکتے۔ پچھلے لیکچرز میں، ہم نے وراثت کی ایک سادہ سی مثال دیکھی: ہمارے پاس والدین کی کلاس تھی
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
}
مرتب کرنے والا فوری طور پر ایک غلطی پیدا کرتا ہے۔ جاوا میں پہلے سے ہی بہت سی کلاسیں نافذ ہیں 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;//так делать можно
}
دوم، ہمارے متغیر کے نام پر توجہ دیں۔ جاوا کانسٹینٹ کا نام دینے کا کنونشن مختلف ہے۔ یہ اونٹ کیس نہیں ہے جس کے ہم عادی ہیں۔ باقاعدہ متغیر کی صورت میں، ہم اسے مستقل مثال کہیں گے، لیکن مستقل کے نام کیپس میں لکھے جاتے ہیں، اور الفاظ کے درمیان (اگر ان میں سے کئی ہیں) ایک انڈر سکور ہوتا ہے - "CONSTANT_EXAMPLE"۔ مستقل کی ضرورت کیوں ہے؟ مثال کے طور پر، اگر آپ کسی پروگرام میں مسلسل کچھ مستقل قدر استعمال کرتے ہیں تو وہ کام آئیں گے۔ ہم کہتے ہیں کہ آپ نے تاریخ میں نیچے جانے اور اکیلے "The Witcher 4" گیم لکھنے کا فیصلہ کیا ہے۔ گیم واضح طور پر مرکزی کردار کے نام کا استعمال کرے گا - "جیرالٹ آف ریویا"۔ اس لائن اور دوسرے ہیروز کے ناموں کو ایک مستقل میں الگ کرنا بہتر ہے: آپ کو جس قدر کی ضرورت ہے اسے ایک جگہ پر محفوظ کیا جائے گا، اور آپ یقینی طور پر اسے دسویں مرتبہ ٹائپ کرتے وقت غلطی نہیں کریں گے۔
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 Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
ہم نے حروف کے ناموں کو مستقل میں الگ کر دیا ہے، اور اب ہم یقینی طور پر ان کی غلط املا نہیں کریں گے، اور ہر بار انہیں ہاتھ سے لکھنے کی ضرورت نہیں ہوگی۔ ایک اور پلس: اگر ہمیں آخر کار پورے پروگرام میں کسی متغیر کی قدر کو تبدیل کرنے کی ضرورت ہے، تو اسے پورے کوڈ میں دستی طور پر دوبارہ کرنے کے بجائے ایک جگہ پر کرنا کافی ہے :)
ناقابل تغیر اقسام
جاوا میں کام کرنے کے دوران، آپ شاید پہلے ہی اس حقیقت کے عادی ہیں کہ پروگرامر تقریباً تمام اشیاء کی حالت کو مکمل طور پر کنٹرول کرتا ہے۔ مطلوب - ایک آبجیکٹ بنایاCat
۔ میں نے چاہا تو نام بدل دیا۔ اس نے چاہا تو اپنی عمر بدل دی، یا کچھ اور۔ لیکن جاوا میں ڈیٹا کی کئی اقسام ہیں جن کی ایک خاص حالت ہے۔ وہ ناقابل تغیر یا ناقابل تغیر ہیں ۔ اس کا مطلب یہ ہے کہ اگر کوئی طبقہ ناقابل تغیر ہے تو اس کی اشیاء کی حالت کو تبدیل نہیں کیا جا سکتا۔ مثالیں؟ آپ حیران ہوں گے، لیکن Immutable کلاس کی سب سے مشہور مثال ہے 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";
"میں جاوا سے پیار کرتا ہوں" اسٹرنگ والی آبجیکٹ تبدیل نہیں ہوئی ہے اور کہیں نہیں گئی ہے۔ یہ محفوظ طریقے سے موجود ہے اور اس کے اندر بالکل وہی متن ہے جو پہلے تھا۔ کوڈ:
str1 = "I love Python";
ابھی ایک اور آبجیکٹ بنایا اور اب متغیر str1
اس کی طرف اشارہ کرتا ہے۔ لیکن ہم کسی بھی طرح سے "میں جاوا سے محبت کرتا ہوں" آبجیکٹ کو متاثر نہیں کر سکتے۔ ٹھیک ہے، آئیے اسے مختلف طریقے سے آزمائیں! کلاس String
طریقوں سے بھری ہوئی ہے، اور ان میں سے کچھ قطار کی حالت کو بدلتے نظر آتے ہیں! مثال کے طور پر، ایک طریقہ ہے replace()
. آئیے اپنی لائن میں لفظ "جاوا" کو لفظ "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()
. منتقل کردہ حروف کی تعداد کی بنیاد پر سٹرنگ کو تراشتا ہے۔ آئیے اپنے پہلے 10 حروف کو تراشتے ہیں:
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);
}
نتیجہ: مجھے جاوا پسند ہے مجھے جاوا پسند ہے کچھ بھی نہیں بدلا ہے۔ اور یہ نہیں ہونا چاہئے. جیسا کہ ہم نے کہا، اشیاء 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
۔ آپ "I love Java" آبجیکٹ کے ساتھ کچھ نہیں کر سکتے ۔ بس ایک نیا آبجیکٹ بنائیں اور لکھیں: "نیا آبجیکٹ = "مجھے جاوا پسند ہے" آبجیکٹ کے ساتھ کچھ ہیرا پھیری کا نتیجہ ۔ کون سی دوسری قسمیں ناقابل تغیر ہیں؟ جس چیز سے آپ کو یقینی طور پر اب یاد رکھنے کی ضرورت ہے - قدیم اقسام سے زیادہ ریپر کی تمام کلاسیں ناقابل تغیر ہیں۔ Integer
, Byte
, Character
, Short
, Boolean
, Long
, Double
, Float
- یہ تمام کلاسیں ناقابل تغیر اشیاء تخلیق کرتی ہیں۔ اس میں بڑی تعداد بنانے کے لیے استعمال ہونے والی کلاسیں بھی شامل ہیں - BigInteger
اور BigDecimal
. ہم نے حال ہی میں مستثنیات سے گزرے اور اس کو چھوا StackTrace
۔ تو: java.lang.StackTraceElement کلاس کی اشیاء بھی ناقابل تغیر ہیں۔ یہ منطقی ہے: اگر کوئی ہمارے اسٹیک پر ڈیٹا کو تبدیل کر سکتا ہے، تو یہ اس کے ساتھ تمام کاموں کی نفی کر سکتا ہے۔ تصور کریں کہ کوئی StackTrace میں جاتا ہے اور OutOfMemoryError کو FileNotFoundException میں تبدیل کرتا ہے ۔ اور آپ کو اس اسٹیک کے ساتھ کام کرنا چاہئے اور خرابی کی وجہ تلاش کرنا چاہئے۔ اور پروگرام فائلوں کو بالکل بھی استعمال نہیں کرتا ہے :) لہذا، محفوظ پہلو پر رہنے کے لیے، ان اشیاء کو ناقابل تغیر بنا دیا گیا تھا۔ ٹھیک ہے، StackTraceElement کے ساتھ یہ کم و بیش واضح ہے۔ کوئی کیوں تاروں کو ناقابل تغیر بنانا چاہے گا؟ اگر ان کی اقدار کو تبدیل کرنا ممکن ہو تو کیا مسئلہ ہو گا۔ یہ شاید اور بھی آسان ہوگا :/ اس کی کئی وجوہات ہیں۔ سب سے پہلے، میموری کو بچانا۔ غیر تبدیل شدہ تاروں کو رکھا جا سکتا ہے String Pool
اور ہر بار نئے بنانے کے بجائے وہی استعمال کیے جا سکتے ہیں۔ دوسرا، حفاظت. مثال کے طور پر، کسی بھی پروگرام میں زیادہ تر لاگ ان اور پاس ورڈ تار ہوتے ہیں۔ ان کو تبدیل کرنے کا امکان اجازت کے ساتھ مسائل کا باعث بن سکتا ہے۔ اور بھی وجوہات ہیں، لیکن ہم نے ابھی تک جاوا سیکھنے میں ان تک رسائی حاصل نہیں کی ہے- ہم بعد میں واپس آئیں گے۔
GO TO FULL VERSION