տեղադրվել է Նարեշ Ջոշի կողմից 2018 թվականի նոյեմբերի 09-ին

Երբ մենք նույն անունով փոփոխական ենք ստեղծում և՛ ծնող, և՛ երեխա դասում, և փորձում ենք մուտք գործել դրան՝ օգտագործելով ծնողի դասի հղումը, որը պահում է երեխայի դասի օբյեկտը, ապա ի՞նչ ենք մենք ստանում:

Սա հասկանալու համար եկեք դիտարկենք ստորև բերված օրինակը, որտեղ մենք հայտարարում ենք x փոփոխականը նույն անունով և՛ Parent, և՛ Child դասերում:

class Parent {
    // Declaring instance variable by name `x`
    String x = "Parent`s Instance Variable";

    public void print() {
        System.out.println(x);
    }
}

class Child extends Parent
{

    // Hiding Parent class's variable `x` by defining a variable in child class with same name.
    String x = "Child`s Instance Variable";

    @Override
    public void print() {
        System.out.print(x);

        // If we still want to access variable from super class, we do that by using `super.x`
        System.out.print(", " + super.x + "\n");
    }
}

Եվ հիմա, եթե փորձենք մուտք գործել x՝ օգտագործելով ստորև բերված կոդը, ինչ System.out.println(parent.x)-ը կտպվի

Parent parent = new Child();
System.out.println(parent.x) // Output -- Parent`s Instance Variable

Դե, ընդհանուր առմամբ, մենք կասենք, որ Child դասը կվերացնի Parent դասում հայտարարված փոփոխականը, և parent.x-ը մեզ կտա այն, ինչ Child's օբյեկտը պահում է: Որովհետև դա նույնն է, ինչ տեղի է ունենում, երբ մենք նույն տեսակի գործողություն ենք կատարում մեթոդների վրա:

Բայց իրականում դա այդպես չէ, և parent.x-ը մեզ արժեք կտա Parent`s Instance Variable-ը, որը հայտարարված է Parent դասում, բայց ինչու:

Քանի որ Java-ում փոփոխականները չեն հետևում պոլիմորֆիզմին, և գերակայությունը կիրառելի է միայն մեթոդների, բայց ոչ փոփոխականների համար: Եվ երբ երեխայի դասի օրինակի փոփոխականն ունի նույն անունը, ինչ մայր դասի օրինակի փոփոխականը, ապա օրինակի փոփոխականն ընտրվում է հղման տեսակից:

Java-ում, երբ մենք Child դասի փոփոխական ենք սահմանում անունով, որը մենք արդեն օգտագործել ենք Parent դասում փոփոխական սահմանելու համար, Child դասի փոփոխականը թաքցնում է ծնողի փոփոխականը, նույնիսկ եթե դրանց տեսակները տարբեր են: Եվ այս հայեցակարգը հայտնի է որպես Փոփոխական թաքցնում

Այլ կերպ ասած, երբ երեխա և ծնող դասը երկուսն էլ ունեն նույն անունով փոփոխական, Child դասի փոփոխականը թաքցնում է ծնող դասի փոփոխականը: Փոփոխականների թաքցման մասին ավելին կարող եք կարդալ Ի՞նչ է փոփոխական ստվերումը և թաքցնելը Java-ում հոդվածում:

Փոփոխական թաքցնելը նույնը չէ, ինչ մեթոդի գերակայումը

Թեև փոփոխականի թաքցումը կարծես փոփոխականի վերացում է, որը նման է մեթոդի գերակայմանը, բայց դա այդպես չէ, գերակայումը կիրառելի է միայն մեթոդների համար, մինչդեռ թաքցումը կիրառելի է փոփոխականների համար:

մեթոդների գերակայման դեպքում, գերակայող մեթոդներն ամբողջությամբ փոխարինում են ժառանգված մեթոդներին, այնպես որ, երբ մենք փորձում ենք մեթոդին մուտք գործել ծնողի հղումից՝ երեխայի օբյեկտը պահելով, երեխայի դասի մեթոդը կանչվում է: Դուք կարող եք ավելին կարդալ գերագնահատման մասին, և թե ինչպես են անտեսված մեթոդները ամբողջությամբ փոխարինում ժառանգված մեթոդներին Ամեն ինչ մեթոդի գերբեռնման և մեթոդի գերակայման մասին, Ինչու պետք է հետևենք մեթոդի վերացման կանոններին:

Բայց փոփոխական թաքցնում երեխայի դասը թաքցնում է ժառանգված փոփոխականները փոխարինելու փոխարեն, ինչը հիմնականում նշանակում է, որ Child դասի օբյեկտը պարունակում է երկու փոփոխականներ, իսկ Child’s փոփոխականը թաքցնում է Ծնողի փոփոխականը: Այսպիսով, երբ մենք փորձում ենք փոփոխականին մուտք գործել Child դասից, այն հասանելի կլինի երեխայի դասից:

Իսկ եթե պարզեցնեմ Օրինակ 8.3.1.1–3. «Java լեզվի ճշգրտման օրինակի փոփոխականների թաքցում.

Երբ մենք հայտարարում ենք փոփոխական Child դասում, որն ունի նույն անունը, օրինակ. x որպես օրինակի փոփոխական Parent դասում, ապա

1. Child class-ի օբյեկտը պարունակում է երկու փոփոխականներ (մեկը ժառանգված է Parent դասից, իսկ մյուսը հայտարարված է Child-ում), սակայն երեխայի դասի փոփոխականը թաքցնում է ծնող դասի փոփոխականը:

2. Քանի որ x-ի հայտարարագիրը Child դասում թաքցնում է x-ի սահմանումը Parent դասում, Child դասի հայտարարագրում, x պարզ անունը միշտ վերաբերում է Child դասում հայտարարված դաշտին: Եվ եթե Child դասի մեթոդների կոդը ցանկանում է վերաբերել Parent դասի x փոփոխականին, ապա դա կարելի է անել որպես super.x:

3. Եթե մենք փորձում ենք մուտք գործել փոփոխական Parent և Child դասերից դուրս, ապա օրինակի փոփոխականն ընտրվում է հղման տեսակից: Այսպիսով, parent2.x արտահայտությունը հետևյալ կոդի մեջ տալիս է փոփոխական արժեքը, որը պատկանում է մայր դասին, նույնիսկ եթե այն պահում է Child-ի օբյեկտը, բայց ((Child) parent2).x-ը մուտք է գործում Child դասի արժեքը, քանի որ մենք նույն հղումն ենք տալիս Childին:

Ինչու է փոփոխական թաքցումը նախագծված այս կերպ

Ուրեմն մենք գիտենք, որ օրինակի փոփոխականներն ընտրվում են հղման տիպից, այլ ոչ թե օրինակի տեսակից, և պոլիմորֆիզմը կիրառելի չէ փոփոխականների համարբայց իրական հարցն այն է, թե ինչու: ինչու են փոփոխականները նախագծված հետևելու թաքցնելու փոխարեն գերակայելու: Քանի որ փոփոխականի գերակայումը կարող է կոտրել ծնողից ժառանգված մեթոդները, եթե մենք փոխենք դրա տեսակը երեխայի դասում:

Մենք գիտենք, որ յուրաքանչյուր երեխա դաս ժառանգում է փոփոխականներ և մեթոդներ (վիճակ և վարքագիծ) իր ծնող դասից: Պատկերացրեք, եթե Java-ն թույլ տա փոփոխականների գերակայում, և մենք փոփոխականի տեսակը փոխենք int-ից Object-ի երեխայի դասում: Այն կխախտի ցանկացած մեթոդ, որն օգտագործում է այդ փոփոխականը, և քանի որ երեխան ժառանգել է այդ մեթոդները ծնողից, կոմպիլյատորը սխալներ կտա child դասում:

Օրինակ:

class Parent {
    int x;

    public int increment() {
        return ++x;
    }

    public int getX() {
        return x;
    }
}

class Child extends Parent {
    Object x;
    // Child is inherting increment(), getX() from Parent and both methods returns an int 
    // But in child class type of x is Object, so increment(), getX() will fail to compile. 
}

Եթե ​​Child.x-ը գերազանցում է Parent.x-ը, ինչպե՞ս կարող են աշխատել increment()-ը և getX()-ը: Ենթադասում այս մեթոդները կփորձեն վերադարձնել սխալ տեսակի դաշտի արժեքը: Եվ ինչպես նշվեց, եթե Java-ն թույլատրում է փոփոխականի գերակայությունը, ապա Child's փոփոխականը չի կարող փոխարինել ծնողի փոփոխականին, և դա կխախտի Liskov փոխարինելիության սկզբունքը (LSP):

Նմանապես, կոմպիլյացիայի ժամանակ փոփոխական մուտքը նույնպես վերաբերվում է հղման տիպին, սակայն, ինչպես մենք քննարկեցինք, փոփոխականները չեն հետևում գերակայող կամ գործարկման ժամանակի պոլիմորֆիզմին, ուստի դրանք չեն փոխարինվում գործարկման ժամանակ երեխայի դասի փոփոխականներով և դեռ վերաբերում են հղման տիպին:

Ընդհանուր առմամբ, ոչ ոք երբեք խորհուրդ չի տա թաքցնել դաշտերը, քանի որ դա դժվարացնում է կոդը կարդալը և շփոթություն է առաջացնում: Այսպիսի շփոթություն չի առաջանա, եթե մենք միշտ հավատարիմ մնանք POJO-ներ ստեղծելու ընդհանուր ուղեցույցներին և ամփոփենք մեր դաշտերը՝ դրանք հայտարարելով որպես մասնավոր և տրամադրենք ստացողներ/սահմանիչներ, ինչպես պահանջվում է, որպեսզի փոփոխականները տեսանելի չլինեն այդ դասից դուրս, և երեխաների դասը չկարողանա մուտք գործել դրանց: .

Դուք կարող եք գտնել ամբողջական կոդը այս Github Repository-ում և խնդրում ենք ազատ զգալ տրամադրել ձեր արժեքավոր կարծիքը:

Սկզբնապես հրապարակվել է www.programmingmitra.com կայքում: