اپریل 2014 کو پیٹر ورہاس کے لکھے ہوئے مضمون کا ترجمہ ۔ مترجم کی طرف سے: اصطلاح " پہلے سے طے شدہ طریقہ " ابھی ابھی جاوا میں نمودار ہوئی ہے اور مجھے یقین نہیں ہے کہ آیا اس کا روسی زبان میں کوئی ترجمہ موجود ہے۔ میں "پہلے سے طے شدہ طریقہ" کی اصطلاح استعمال کروں گا، حالانکہ مجھے نہیں لگتا کہ یہ مثالی ہے۔ میں آپ کو مزید کامیاب ترجمے پر بات کرنے کی دعوت دیتا ہوں۔
پہلے سے طے شدہ طریقہ کیا ہے؟
اب، جاوا 8 کے اجراء کے ساتھ، آپ انٹرفیس میں نئے طریقے شامل کر سکتے ہیں تاکہ انٹرفیس ان کلاسوں کے ساتھ مطابقت رکھتا ہو جو اسے نافذ کرتی ہیں۔ یہ بہت اہم ہے اگر آپ ایک لائبریری تیار کر رہے ہیں جو کیو سے نیویارک تک بہت سے پروگرامرز استعمال کرتے ہیں۔ جاوا 8 سے پہلے، اگر آپ کسی لائبریری میں انٹرفیس کی تعریف کرتے ہیں، تو آپ اس میں طریقے شامل نہیں کر سکتے تھے اس خطرے کے بغیر کہ آپ کے انٹرفیس کو چلانے والی کچھ ایپلیکیشن اپ ڈیٹ ہونے پر ٹوٹ جائے گی۔ تو، جاوا 8 میں آپ اب اس سے ڈر نہیں سکتے؟ نہیں تم نہیں کر سکتے. انٹرفیس میں پہلے سے طے شدہ طریقہ شامل کرنا کچھ کلاسوں کو ناقابل استعمال بنا سکتا ہے۔ آئیے پہلے طے شدہ طریقوں کے بارے میں اچھی چیزوں کو دیکھیں۔ جاوا 8 میں، طریقہ کو براہ راست انٹرفیس میں لاگو کیا جا سکتا ہے۔ (ایک انٹرفیس میں جامد طریقوں کو بھی لاگو کیا جا سکتا ہے، لیکن یہ ایک اور کہانی ہے۔) ایک انٹرفیس میں لاگو کردہ طریقہ کو ڈیفالٹ میتھڈ کہا جاتا ہے، اور اسے ڈیفالٹ کلیدی لفظ سے ظاہر کیا جاتا ہے ۔ اگر ایک کلاس انٹرفیس کو لاگو کرتی ہے، تو یہ انٹرفیس میں لاگو کیے گئے طریقوں کو لاگو کر سکتا ہے، لیکن اس کی ضرورت نہیں ہے۔ کلاس کو پہلے سے طے شدہ نفاذ کی وراثت ملتی ہے۔ یہی وجہ ہے کہ جب ان کے نافذ کردہ انٹرفیس کو تبدیل کرتے وقت کلاسوں میں ترمیم کرنا ضروری نہیں ہے۔ایک سے زیادہ وراثت؟
چیزیں مزید پیچیدہ ہو جاتی ہیں اگر کوئی کلاس ایک سے زیادہ (کہیں، دو) انٹرفیس کو لاگو کرتی ہے، اور وہ ایک ہی طے شدہ طریقہ کو نافذ کرتی ہے۔ کلاس کو کون سا طریقہ وراثت میں ملے گا؟ جواب کوئی نہیں ہے۔ اس صورت میں، کلاس کو خود طریقہ کار کو نافذ کرنا ہوگا (یا تو براہ راست یا کسی اور کلاس سے وراثت میں لے کر)۔ صورت حال ایسی ہی ہے اگر صرف ایک انٹرفیس میں ڈیفالٹ طریقہ ہو، اور دوسرے میں وہی طریقہ خلاصہ ہو۔ Java 8 نظم و ضبط رکھنے اور مبہم حالات سے بچنے کی کوشش کرتا ہے۔ اگر ایک سے زیادہ انٹرفیس میں طریقوں کا اعلان کیا جاتا ہے، تو کلاس کے ذریعہ کوئی ڈیفالٹ نفاذ وراثت میں نہیں ملتا ہے - آپ کو ایک تالیف کی خرابی ملے گی۔ اگرچہ، اگر آپ کی کلاس پہلے ہی مرتب ہو چکی ہے تو آپ کو تالیف کی غلطی نہیں ہو سکتی۔ جاوا 8 اس سلسلے میں کافی مضبوط نہیں ہے۔ اس کی وجوہات ہیں، جن پر میں بحث نہیں کرنا چاہتا (مثال کے طور پر: جاوا ریلیز پہلے ہی جاری ہو چکی ہے اور بات چیت کا وقت بہت گزر چکا ہے اور عام طور پر، یہ ان کے لیے جگہ نہیں ہے)۔- فرض کریں کہ آپ کے پاس دو انٹرفیس ہیں اور ایک کلاس ان دونوں کو لاگو کرتی ہے۔
- انٹرفیس میں سے ایک پہلے سے طے شدہ طریقہ m() کو نافذ کرتا ہے۔
- آپ تمام انٹرفیس اور کلاس کو مرتب کرتے ہیں۔
- آپ ایک ایسے انٹرفیس کو تبدیل کرتے ہیں جس میں m() طریقہ نہیں ہے اسے تجریدی طریقہ قرار دے کر۔
- آپ صرف ترمیم شدہ انٹرفیس مرتب کرتے ہیں۔
- کلاس شروع کریں۔
- خلاصہ m() طریقہ کے ساتھ انٹرفیس کو تبدیل کریں اور پہلے سے طے شدہ نفاذ شامل کریں۔
- ترمیم شدہ انٹرفیس کو مرتب کریں۔
- کلاس چلائیں: غلطی۔
مثال کوڈ
مندرجہ بالا کو ظاہر کرنے کے لیے، میں نے C.java کلاس کے لیے ایک ٹیسٹ ڈائرکٹری اور I1.java اور I2.java فائلوں میں انٹرفیس کے لیے 3 ذیلی ڈائریکٹریز بنائی ہیں۔ ٹیسٹ کے لیے روٹ ڈائرکٹری C.java کلاس کے لیے سورس کوڈ پر مشتمل ہے۔ بیس ڈائرکٹری انٹرفیس کا ایک ورژن پر مشتمل ہے جو عمل درآمد اور تالیف کے لیے موزوں ہے: انٹرفیس I1 کا ایک طے شدہ طریقہ ہے m(); I2 انٹرفیس میں ابھی تک کوئی طریقہ نہیں ہے۔ کلاس کا ایک طریقہ ہےmain
لہذا ہم اسے جانچنے کے لیے اس پر عمل کر سکتے ہیں۔ یہ چیک کرتا ہے کہ آیا کوئی کمانڈ لائن دلائل موجود ہیں، لہذا ہم اسے آسانی سے یا تو کال کے ساتھ یا اس کے بغیر چلا سکتے ہیں m()
۔
~/github/test$ cat C.java
public class C implements I1, I2 {
public static void main(String[] args) {
C c = new C();
if( args.length == 0 ){
c.m();
}
}
}
~/github/test$ cat base/I1.java
public interface I1 {
default void m(){
System.out.println("hello interface 1");
}
}
~/github/test$ cat base/I2.java
public interface I2 {
}
آپ کمانڈ لائن سے کلاس کو مرتب اور چلا سکتے ہیں۔
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
مطابقت پذیر ڈائرکٹری میں I2 انٹرفیس کا ایک ورژن شامل ہے جو m() طریقہ کو خلاصہ قرار دیتا ہے، اور تکنیکی وجوہات کی بناء پر، I1.java کی ایک غیر ترمیم شدہ کاپی۔
~/github/test$ cat compatible/I2.java
public interface I2 {
void m();
}
اس طرح کا سیٹ C کلاس کو مرتب کرنے کے لیے استعمال نہیں کیا جا سکتا:
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
^
1 error
غلطی کا پیغام بہت درست ہے۔ تاہم، ہمارے پاس پچھلی تالیف سے C.class ہے اور، اگر ہم انٹرفیس کو ہم آہنگ ڈائریکٹری میں مرتب کرتے ہیں، تو ہمارے پاس دو انٹرفیس ہوں گے جو اب بھی کلاس چلانے کے لیے استعمال کیے جاسکتے ہیں:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
تیسری ڈائرکٹری - wrong
- ورژن I2 پر مشتمل ہے، جو طریقہ کا بھی اعلان کرتی ہے m()
:
~/github/test$ cat wrong/I2.java
public interface I2 {
default void m(){
System.out.println("hello interface 2");
}
}
آپ کو تالیف کے بارے میں بھی فکر کرنے کی ضرورت نہیں ہے۔ اگرچہ طریقہ دو بار اعلان کیا گیا ہے، کلاس اب بھی استعمال کیا جا سکتا ہے اور چلایا جا سکتا ہے جب تک کہ m() طریقہ نہیں کہا جاتا ہے. یہ وہی ہے جس کے لئے ہمیں کمانڈ لائن دلیل کی ضرورت ہے:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
at C.m(C.java)
at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$
GO TO FULL VERSION