JavaRush /Java блогу /Random-KY /Java'да дайындоо жана инициализация
Viacheslav
Деңгээл

Java'да дайындоо жана инициализация

Группада жарыяланган

Киришүү

Компьютердик программалардын негизги максаты – маалыматтарды иштетүү. Маалыматтарды иштетүү үчүн сиз аны кандайдыр бир жол менен сакташыңыз керек. Мен маалыматтардын сакталышын түшүнүүнү сунуштайм.
Java'да дайындоо жана инициализация - 1

Өзгөрмөлөр

Өзгөрмөлөр ар кандай маалыматтарды сактоочу контейнерлер. Келгиле, Oracleдан расмий окуу куралын карап көрөлү: Мүчө өзгөрмөлөрүн жарыялоо . Бул окуу куралына ылайык, өзгөрмөлөрдүн бир нече түрлөрү бар:
  • Fields : класста жарыяланган өзгөрмөлөр;
  • Локалдык өзгөрмөлөр : метод же code блогундагы өзгөрмөлөр;
  • Параметрлер : методдун декларациясында өзгөрмөлөр (кол коюуда).
Бардык өзгөрмөлөр өзгөрмөнүн түрү жана өзгөрмө аты болушу керек.
  • Өзгөрмөнүн түрү өзгөрмө кандай маалыматтарды (б.а. ал кандай маалыматтарды сактай аларын) көрсөтөт. Белгилүү болгондой, өзгөрмөнүн түрү примитив эмес (примитивдер ) же an object болушу мүмкүн . Объекттин өзгөрмөлөрү менен алардын түрү белгилүү бир класс тарабынан сүрөттөлөт.
  • Өзгөрмө аты төө тамгасы менен кичи тамга болушу керек. Ат коюу жөнүндө көбүрөөк окуй аласыз " Variables:Naming ".
Ошондой эле, эгерде класстык деңгээлдеги өзгөрмө, б.а. класс талаасы болуп саналат, ага кирүү модификатору көрсөтүлүшү мүмкүн. Көбүрөөк маалымат үчүн Класстын мүчөлөрүнө кирүүнү көзөмөлдөө .

Variable Declaration

Ошентип, биз өзгөрмө эмне экенин эстейбиз. Өзгөрмө менен иштей баштоо үчүн, аны жарыялоо керек. Биринчиден, жергorктүү өзгөрмө карап көрөлү. Ыңгайлуу болуу үчүн IDEдин ордуна, биз tutorialspoint'тин онлайн чечимин колдонобуз: Online IDE . Келгиле, бул жөнөкөй программаны онлайн IDEде иштетели:
public class HelloWorld{
    public static void main(String []args){
        int number;
        System.out.println(number);
    }
}
numberОшентип, сиз көрүп тургандай, биз аты жана түрү менен локалдык өзгөрмө жарыяладык int. Биз "Аткаруу" баскычын басып, катаны алабыз:
HelloWorld.java:5: error: variable number might not have been initialized
        System.out.println(number);
Не болду? Биз өзгөрмө жарыяладык, бирок анын маанисин инициализациялаган жокпуз. Белгилей кетсек, бул ката аткаруу убагында эмес (башкача айтканда, Runtime эмес), компиляция убагында болгон. Акылдуу компилятор локалдык өзгөрмө ага жетүү алдында инициализацияланарын текшерди. Демек, мындан төмөнкү сөздөр келип чыгат:
  • Жергorктүү өзгөрмөлөргө алар инициализациялангандан кийин гана кирүү керек;
  • Жергorктүү өзгөрмөлөр демейки маанилерге ээ эмес;
  • Жергorктүү өзгөрмөлөрдүн маанилери компиляция убагында текшерилет.
Ошентип, биз өзгөрмө инициализацияланышы керек деп айтышат. Өзгөрмөлөрдү инициализациялоо - бул өзгөрмөгө маани берүү. Келгиле, бул эмне жана эмне үчүн экенин аныктап көрөлү.

Жергorктүү өзгөрмө инициализациялоо

Өзгөрмөлөрдү инициализациялоо Javaдагы эң татаал темалардын бири, анткени... эс тутум менен иштөө, JVM ишке ашыруу, JVM спецификациясы жана башка коркунучтуу жана татаал нерселер менен тыгыз байланыштуу. Бирок, сиз, жок эле дегенде, кандайдыр бир деңгээлде түшүнүүгө аракет кылсаңыз болот. Жөнөкөйдөн татаалга карай кетели. Өзгөрмөлөрдү инициализациялоо үчүн биз дайындоо операторун колдонобуз жана мурунку codeубуздагы сапты өзгөртөбүз:
int number = 2;
Бул параметрде каталар болбойт жана маани экранда көрсөтүлөт. Бул учурда эмне болот? Келгиле, ой жүгүртүүгө аракет кылалы. Эгерде биз өзгөрмөгө маани ыйгаргыбыз келсе, анда ал өзгөрмө маанини сакташын каалайбыз. Көрсө, баалуулук бир жерде сакталышы керек, бирок кайда? Дисктеби? Бирок бул өтө жай жана бизге чектөө киргизиши мүмкүн. Көрсө, биз “бул жерде жана азыр” маалыматтарды тез жана эффективдүү сактай турган бирден-бир жер – бул эс. Бул эс тутумда бир аз орун бөлүшүбүз керек дегенди билдирет. Бул чыныгы. Өзгөрмө инициализацияланганда, ал үчүн биздин программа аткарыла турган java процессине бөлүнгөн эс тутумда орун бөлүнөт. Java процессине бөлүнгөн эс бир нече аймактарга же зоналарга бөлүнөт. Алардын кайсынысы мейкиндикти бөлүштүрө турганы өзгөрмө кайсы түргө жарыяланганына жараша болот. Эс төмөнкү бөлүктөргө бөлүнөт: үймөк, стек жана үймөк эмес . Стек эс тутумунан баштайлы. Стек стек деп которулат (мисалы, китептер стек). Бул LIFO (акыркы кирген, биринчи чыккан) маалымат структурасы. Башкача айтканда, үйүлгөн китептер сыяктуу. Ага китептерди кошкондо үстүнө коёбуз, ал эми алып кеткенибизде үстүн (б.а. эң акыркы кошулганын) алабыз. Ошентип, биз программабызды ишке киргизебиз. Белгилүү болгондой, Java программасы JVM, башкача айтканда Java виртуалдык машинасы тарабынан аткарылат. JVM программанын аткарылышы кайсы жерден башталышы керектигин бorши керек. Бул үчүн, биз "кирүү чекити" деп аталган негизги ыкманы жарыялайт. JVMде аткаруу үчүн негизги жип (Thread) түзүлөт. Жип түзүлгөндө, ал эстутумда өзүнүн стекине бөлүнөт. Бул стек рамкалардан турат. Ар бир жаңы ыкма жипте аткарылганда, ал үчүн жаңы кадр бөлүнөт жана стектин башына кошулат (китептердин стекиндеги жаңы китеп сыяктуу). Бул кадр an objectилерге жана примитивдүү типтерге шилтемелерди камтыйт. Ооба, ооба, биздин int стекте сакталат, анткени... int примитивдүү түрү. Кадрды бөлүштүрүүдөн мурун, JVM ал жерде эмнени сактоо керектигин түшүнүшү керек. Дал ушул себептен улам, биз "өзгөрмө инициализацияланбаган болушу мүмкүн" катасын алабыз, анткени ал инициализацияланбаса, анда JVM биз үчүн стек даярдай алbyte. Ошондуктан, программаны компиляциялоодо, акылдуу компилятор ката кетирбөөгө жана бардыгын бузууга жардам берет. (!) Түшүнүктүү болушу үчүн мен супер-дупер макаланы сунуштайм: “ Java Stack and Heap: Java Memory Allocation Tutorial ”. Ал бирдей сонун видеого шилтеме кылат:
Методдун аткарылышы аяктагандан кийин, бул методдор үчүн бөлүнгөн фреймдер жиптин стекинен жок кылынат жана алар менен бирге бардык маалыматтар менен бул кадр үчүн бөлүнгөн эстутум тазаланат.

Жергorктүү an objectтин өзгөрмөлөрүн инициализациялоо

Келгиле, codeубузду дагы бир аз татаалыраак кылып өзгөртөлү:
public class HelloWorld{

    private int number = 2;

    public static void main(String []args){
        HelloWorld object = new HelloWorld();
        System.out.println(object.number);
    }

}
Бул жерде эмне болот? Келгиле, бул тууралуу дагы сүйлөшөлү. JVM программаны кайсы жерден аткарышы керектигин билет, б.а. ал негизги ыкманы көрөт. Ал жипти түзөт, ал үчүн эстутумду бөлөт (анткени, жип аткаруу үчүн керектүү маалыматтарды бир жерде сакташы керек). Бул жипте негизги ыкма үчүн кадр бөлүнгөн. Андан кийин HelloWorld an objectин түзөбүз. Бул an object мындан ары стекте эмес, үймөктө түзүлөт. Анткени an object примитивдүү тип эмес, an objectтин түрү. Жана стек үймөктө an objectке шилтемени гана сактайт (биз бул an objectке кандайдыр бир жол менен жетүүбүз керек). Андан кийин, негизги ыкманын стекинде, println ыкмасын аткаруу үчүн фреймдер бөлүнөт. Негизги ыкманы аткаргандан кийин, бардык рамкалар жок кылынат. Эгерде кадр жок кылынса, анда бардык маалыматтар жок кылынат. Объект an objectи дароо жок кылынbyte. Биринчиден, ага шилтеме жок кылынат жана ошентип, мындан ары эч ким an object an objectине кайрылbyte жана эстутумдагы бул an objectке кирүү мындан ары мүмкүн болбой калат. Акылдуу JVMдин бул үчүн өзүнүн механизми бар - таштанды жыйноочу (таштанды жыйноочу же кыскача GC). Андан кийин ал эс тутумунан эч ким шилтеме кылбаган an objectтерди алып салат. Бул процесс кайрадан жогоруда берилген шилтемеде сүрөттөлгөн. Жада калса түшүндүрмөсү бар видео да бар.

Талааларды баштоо

Класста көрсөтүлгөн талааларды инициализациялоо талаанын статикалык же статикалык эместигине жараша өзгөчө түрдө ишке ашат. Эгерде талаада static ачкыч сөзү болсо, анда бул талаа класстын өзүнө тиешелүү, ал эми статик деген сөз көрсөтүлбөсө, анда бул талаа класстын инстанциясына тиешелүү. Муну бир мисал менен карап көрөлү:
public class HelloWorld{
    private int number;
    private static int count;

    public static void main(String []args){
        HelloWorld object = new HelloWorld();
        System.out.println(object.number);
    }
}
Бул мисалда талаалар ар кандай убакта инициализацияланган. Сан талаасы HelloWorld класс an objectи түзүлгөндөн кийин инициализацияланат. Бирок класс Java виртуалдык машинасы тарабынан жүктөлгөндө эсептөө талаасы инициализацияланат. Класс жүктөө өзүнчө тема, андыктан аны бул жерде аралаштырбайбыз. Статикалык өзгөрмөлөр класс иштөө убагында белгилүү болгондо инициализацияланарын билүү керек. Бул жерде дагы бир нерсе маанилүү, сиз муну байкагансыз. Биз эч жерде маанини көрсөткөн жокпуз, бирок ал иштейт. Жана чынында. Талаалар болгон өзгөрмөлөр, эгерде аларда көрсөтүлгөн маани жок болсо, алар демейки маани менен инициализацияланат. Сандык маанилер үчүн бул калкыма чекиттер үчүн 0 же 0,0. Буль үчүн бул жалган. Жана бардык an object түрүндөгү өзгөрмөлөр үчүн маани нөл болот (бул тууралуу кийинчерээк сүйлөшөбүз). Көрсө, бул эмне үчүн? Бирок an objectтер үймөктө (үймөктө) түзүлгөндүктөн. Бул аймак менен иштөө Runtime режиминде аткарылат. Жана биз бул өзгөрмөлөрдү аткаруу учурунда инициализациялай алабыз, стектен айырмаланып, эстутуму аткарууга чейин даярдалышы керек. Javaда эстутум ушундай иштейт. Бирок бул жерде дагы бир өзгөчөлүк бар. Бул кичинекей чыгарма эс тутумдун ар кайсы бурчтарына тийет. Эсибизде болгондой, негизги метод үчүн Стек эстутумунда кадр бөлүнгөн. Бул кадр үймөк эсинде an objectке шилтемени сактайт. Бирок анда эсеп кайда сакталат? Эсибизде болгондой, бул өзгөрмө an object үймөктө түзүлгөнгө чейин дароо инициализацияланат. Бул чындап эле татаал суроо. Java 8ге чейин PERMGEN деп аталган эс тутум аймагы болгон. Java 8ден баштап бул аймак өзгөрүп, METASPACE деп аталды. Негизинен, статикалык өзгөрмөлөр класс аныктамасынын бир бөлүгү болуп саналат, б.а. анын метадайындары. Ошондуктан, анын METASPACE метадайындар репозиторийинде сакталганы логикалык. MetaSpace ошол эле Non-Heap эс аймагына кирет жана анын бир бөлүгү болуп саналат. Ошондой эле өзгөрмөлөрдүн жарыялоо тартиби эске алынарын эске алуу маанилүү. Мисалы, бул codeдо ката бар:
public class HelloWorld{

    private static int b = a;
    private static int a = 1;

    public static void main(String []args){
        System.out.println(b);
    }

}

null деген эмне

Жогоруда айтылгандай, an object түрлөрүнүн өзгөрмөлөрү, эгерде алар класстын талаалары болсо, демейки маанилерге инициализацияланат жана ал демейки маани нөл болот. Бирок Javaда нөл деген эмне? Эсте турган биринчи нерсе, примитивдүү типтер нөл болушу мүмкүн эмес. Жана баары, анткени null - бул эч жерде, эч кандай an objectке шилтеме кылбаган өзгөчө шилтеме. Демек, бир гана an object өзгөрмө нөл болушу мүмкүн. Түшүнүү үчүн маанилүү болгон экинчи нерсе - бул нөл шилтеме. Мен алардын салмагын да айтам. Бул темада сиз stackoverflow боюнча суроону окуй аласыз: " Нөл өзгөрмө эстутумда орун талап кылабы ?".

Инициализация блоктору

Өзгөрмөлөрдү инициализациялоону карап жатканда, инициализация блокторун эске албай коюу күнөө болуп калат. Бул төмөнкүдөй көрүнөт:
public class HelloWorld{

    static {
        System.out.println("static block");
    }

    {
        System.out.println("block");
    }

    public HelloWorld () {
        System.out.println("Constructor");
    }

    public static void main(String []args){
        HelloWorld obj = new HelloWorld();
    }

}
Чыгуу тартиби болот: статикалык блок, блок, Конструктор. Көрүнүп тургандай, инициализациялоо блоктору конструктордон мурун аткарылат. Жана кээде бул инициализациянын ыңгайлуу каражаты болушу мүмкүн.

Корутунду

Бул кыскача баяндама анын кандайча жана эмне үчүн иштээри жөнүндө бир аз түшүнүк бере алды деп үмүттөнөм. #Вячеслав
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION