ინიციალიზაცია ჯავაში საკმაოდ ნიუანსური და ერთი შეხედვით საკმაოდ რთული საკითხია, თუმცა სინამდვილეში ყველაფერი ზედმეტად მარტივი და ლოგიკურია. ინიციალიზაცია იყოფა რამდენიმე ნაწილად და ყოველთვის ერთი და იგივე მიმდევრობით სრულდება მიუხედავად კონკრეტული იერარქიის სიღრმისა და სირთულისა.
პირველ რიგში მნიშვნელოვანია ვიცოდეთ თუ როგორ ხდება კლასების ჩატვირთვა ამ ენაში. ჯავაში კლასები იტვირთება დინამიურად საჭიროების მიხედვით და ეს ხდება მხოლოდ ერთხელ.
რა დროს იტვირთება კლასი? კლასის ჩატვირთვა ხდება მხოლოდ მაშინ როდესაც მივმართავთ მის რომელიმე სტატიკურ წევრს(იგულისხმება რომ ასეთ წევრს უნდა გააჩნდეს შესაბამისი წვდომის მოდიფიკატორი რათა მასზე წვდომა იყოს შესაძლებელი). გარდა კლასის ჩვეულებრივი სტატიკური ცვლადებისა და მეთოდებისა უნდა აღინიშნოს რომ კლასის კონსტრუქტორიც ასევე არის სტატიკური(თუმცა არაცხადად, რადგან მას არ ესაჭიროება static გასაღები სიტყვის მითითება). გამომდინარე აქედან შეგვიძლია ვთქვათ რომ კლასის ობიექტის შექმნისას როდესაც new ოპერატორის შემდეგ მივმართავთ სასურველი კლასის კონსტრუქტორს(მაგ. TestClass t = new TestClass()), სინამდვილეში მივმართავთ კლასის სტატიკურ წევრს და იმ შემთხვევაში თუ კლასი ჯერ არ არის ჩატვირთული ხდება მისი ჩატვირთვა.
ზოგადად მიჩნეულია რომ კლასის კონსტრუქტორი არის ისეთი წევრი რომელიც აუცილებლად სრულდება პირველად(რადგან იგი იძახება პირველი) ვიდრე შესრულდება კოდის სხვა ნაწილი, თუმცა ეს ასე არ არის. (იხ. კონსტრუქტორების დეტალები)
იმისათვის რათა უფრო დეტალურად გავიგოთ ინიციალიზაციის მიმდევრობა საჭიროა გამოვყოთ ამ პროცესში მონაწილე ყოველი ნაწილი.
1) კლასის სტატიკური ცვლადების ინიციალიზაცია
კლასის სტატიკურ ცვლადებს ენიჭებათ საწყისი მნიშვნელობები(თუ ცხადად არ არის მითითებული რაიმე კონკრეტული მნიშვნელობა)
2) კლასის სტატიკური ინიციალიზაციის ბლოკები
სტატიკური ინიციალიზაციის ბლოკები სრულდება მხოლოდ ერთხელ კლასის ჩატვირთვისას და იმ მიმდევრობით რა მიმდევრობითაც არიან ასეთი ბლოკები განსაზღვრული კლასში(იხ. სტატიკური ცვლადები და მეთოდები)
3) კლასის ცვლადების ინიციალიზაცია
კლასის ცვლადებს ენიჭებათ საწყისი მნიშვნელობები(თუ ცხადად არ არის მითითებული რაიმე კონკრეტული მნიშვნელობა) კლასის ყოველი ახალი ობიექტის შექმნისას
4) კლასის ინიციალიზციის ბლოკები
კლასის ინიციალიზაციის ბლოკები სრულდება კლასის ყოველი ახალი ობიექტის შექმნისას იმ მიმდევრობით რა მიმდევრობითაც არიან ასეთი ბლოკები განსაზღვრული კლასში.
5) კონსტრუქტორები
კონსტრუქტორი შესრულდება მხოლოდ მაშინ როდესაც დასრულდება ყველა ზემოთ ჩამოთვლილი ინიციალიზაციის ეტაპი.
ჩამოთვლილი ეტაპები გარდა იმისა რომ ვრცელდება კონკრეტულ ერთ კლასზე – ასევე ვრცელდება კლასების მთელ იერარქიაზე რა სიღრმისაც არ უნდა იყოს იერარქია ინიციალიზაციის პროცესი შესრულდება ზევიდან(იერარქიის სათავიდან) ქვევით და ზუსთად ზემოთ აღწერილი მიმდევრობით
ქვემოთ ნაჩვენებია მარტივი იერარქია რომელიც შედგება ორი TestParent და TestChild კლასისგან, სადაც TestChild კლასი არის TestParent კლასის მემკვიდრე. ორივე კლასში გამოყენებულია ყველა ტიპის ინიციალიზაციის ბლოკი და ასევე კონსტრუქტორები. მესამე InitTest კლასი გამოიყენება ინიციალიზაციის მიმდევრობის ტესტირებისათვის.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | class TestParent { private static String str; private int t; /** * Static initialization block */ static { str = "TestParent Class Static Initialization"; System.out.println(str); } /** * Initialization block */ { t = 24; System.out.println("TestParent Class Initialization block: int t = " + t); } /** * Test Class Constructor */ TestParent() { System.out.println("TestParent Class Constructor: int t = " + t); } } class TestChild extends TestParent { /** * Private static variable */ private static String str; /** * Static initialization block */ static { str = "TestChild Class Static Initialization"; System.out.println(str); } /** * Initialization block */ { System.out.println("TestChild Class Initialization block"); } /** * TestOne Class Constructor */ TestChild() { System.out.println("TestChild Class Constructor"); } static void test() { System.out.println("TestChild's static test method"); } } public class InitTest { public static void main(String[] args) { /** * Create TestChild class instance */ new TestChild(); /** * Invoce TestChild class' static test method */ //TestChild.test(); } } |
კოდის დაკომპილირებისა და გაშვების შემდეგ new TestChild(); გამოსახულების შესრულების შემდეგ მივიღებთ ქვემოთ ნაჩვენებ შედეგს:
TestParent Class Static Initialization TestChild Class Static Initialization TestParent Class Initialization block: int t = 24 TestParent Class Constructor: int t = 24 TestChild Class Initialization block TestChild Class Constructor
თუ გავაანალიზებთ შედეგს დავინახავთ რომ ინიციალიზაცია იერარქიაში ხდება ზევიდან ქვევით, მიუხედავად იმისა რომ new TestChild(); გამოსახულება ქმნის TestChild კლასის ობიექტის, პირველად მისი მშობელი TestParent კლასის ყველა ინიციალიზაციის ბლოკი სრულდება, შემდეგ სრულდება მშობელი კლასის კონსტრუქტორი ხოლო უკვე შემდეგ სრულდება თვით TestChild კლასის ინიციალიზაციის ბლოკები და ბოლოს კი კონსტრუქტორი.
თუ გავაკომენტარებით new TestChild(); გამოსახულებას და შევასრულებთ მხოლოდ TestChild.test(); გამოსახულებას შედეგი იქნება შემდეგი სახის:
TestParent Class Static Initialization TestChild Class Static Initialization TestChild's static test method
რადგან ამ შემხვევაში გამოვიძახეთ TestChild კლასის სტატიკური test() მეთოდი ამ შემთხვევაში მოხდა იერარქიაში არსებული მხოლოდ სტატიკური წევრების ინიციალიზაცია და ასევე სტატიკური ინიციალიზაციის ბლოკების შესრულება, თუმცა ზუსტად იგივე მიმდევრობით რა მიმდევრობითაც ეს პირველ შემთხვევაში განხორციელდა.
რის გამო გამოიყენება ინიციალიზაციის ასეთი მიმდევორბა ჯავაში? მიზეზი ამისა მარტივია და სავსებით ლოგიკური. როდესაც ვიყენებთ რომელიმე კლასს რომელიც არის გარკვეული იერარქიის ნაწილი, გარდა ამ კლასის ჩატვირთვისა და ინიციალიზაციისა ასევე იტვირთება(თუ არ არის ჩატვირთული) და ინიციალიზირდება იერარქიაში ამ კლასის ზემოთ მდგომი ყველა კლასი, გამომდინარე იქიდან რომ იერარქიის სირთულის დ სიღრმის განსაზღვრა წინასწარ შეუძლებელია(ამის არანაირი საჭიროებაც არ არსებობს) მნიშვნელოვანი დეტალია ის რომ თითოეული კლასი იქმნება გარკვეული მიზნით და სავსებით ბუნებრივია რომ ასეთ კლასებს შეიძლება გააჩნდეთ მათთვის დამახასიათებელი მდგომარება, ხოლო მდგომარეობა განისაზღვრება კლასის ცვლადების მნიშვნელობებით. იმ შემთხვევაში თუ არ მოხდება ზევიდან ქვევით ყველა კლასის სწორი ინიციალიზაცია იერარქიაში ქვემოთ მდგომი კლასის მუშაობის სისწორე თავისთავად კითხვის ნიშნის ქვეშ დგება, რაც სავსებით ბუნებრივსა და ლოგიკურს ხდის კლასების ინიციალიზაციის ასეთ მიმდევრობას.
ტეგები: Java
ძალიან საინტერესო და საჭირო სტატიაა, ეს თემა საერთოდ არ ვიცოდი
მადლობა.
ეს ყველაფერი კაი მაგრამ ჯარში რომ წახვალ რა გვეშველება ავტორო
macbook-ს წაიღებ
?
XAXAN
არა ჯარში ნამდვილად არ მინდა მაკბუკი და მსგავსი დივაისები