JavaRush /Java блогы /Random-KK /Java тілінде тағайындау және инициализация
Viacheslav
Деңгей

Java тілінде тағайындау және инициализация

Топта жарияланған

Кіріспе

Компьютерлік бағдарламалардың негізгі мақсаты – мәліметтерді өңдеу. Деректерді өңдеу үшін оны қандай да бір жолмен сақтау керек. Мен деректердің қалай сақталатынын түсінуді ұсынамын.
Java тілінде тағайындау және инициализация - 1

Айнымалылар

Айнымалылар - кез келген деректерді сақтайтын контейнерлер. Oracle ресми оқулығын қарастырайық: мүше айнымалыларын жариялау . Осы оқулыққа сәйкес айнымалылардың бірнеше түрі бар:
  • Өрістер : сыныпта жарияланған айнымалылар;
  • Жергілікті айнымалылар : әдіс немесе code блогындағы айнымалылар;
  • Параметрлер : әдіс декларациясындағы айнымалылар (қолтаңбада).
Барлық айнымалылардың айнымалы типі және айнымалы атауы болуы керек.
  • Айнымалының түрі айнымалының қандай деректерді көрсететінін (яғни қандай деректерді сақтай алатынын) көрсетеді. Біз білетіндей, айнымалының типі қарабайыр (қарабайыр емес ) емес, қарабайыр (қарабайырлар ) немесе нысан болуы мүмкін. Объектінің айнымалыларымен олардың түрі белгілі бір сыныппен сипатталады.
  • Айнымалы атауы түйе әріпінде кіші әріппен жазылуы керек. Атау туралы толығырақ « Айнымалылар:Атау » бөлімінен оқи аласыз .
Сондай-ақ, егер сынып деңгейінің айнымалысы, яғни. класс өрісі болып табылады, оған кіру модификаторын көрсетуге болады. Қосымша мәліметтер алу үшін Сынып мүшелеріне қатынасты бақылау бөлімін қараңыз .

Айнымалылар туралы декларация

Сонымен, біз айнымалының не екенін еске түсіреміз. Айнымалымен жұмыс істеуді бастау үшін оны жариялау керек. Алдымен жергілікті айнымалыны қарастырайық. Ыңғайлы болу үшін IDE орнына, біз оқу құралдарының онлайн шешімін қолданамыз: Online IDE . Осы қарапайым бағдарламаны олардың онлайн IDE-де іске қосайық:
public class HelloWorld{
    public static void main(String []args){
        int number;
        System.out.println(number);
    }
}
numberСонымен, сіз көріп отырғандай, біз name және type бар жергілікті айнымалыны жарияладық int. Біз «Орындау» түймесін басып, қатені аламыз:
HelloWorld.java:5: error: variable number might not have been initialized
        System.out.println(number);
Не болды? Біз айнымалыны жарияладық, бірақ оның мәнін инициализацияламадық. Айта кету керек, бұл қате орындалу уақытында емес (яғни, Runtime емес), компиляция уақытында болды. Смарт компилятор жергілікті айнымалы мәнге қол жеткізбес бұрын инициализацияланатынын немесе жоқтығын тексерді. Демек, осыдан келесі мәлімдемелер шығады:
  • Жергілікті айнымалы мәндерге олар инициализацияланғаннан кейін ғана қол жеткізу керек;
  • Жергілікті айнымалылардың әдепкі мәндері жоқ;
  • Жергілікті айнымалылардың мәндері компиляция уақытында тексеріледі.
Сонымен, бізге айнымалыны инициализациялау керек деп айтады. Айнымалыны инициализациялау - айнымалыға мән беру. Содан кейін оның не екенін және неге екенін анықтайық.

Жергілікті айнымалыны инициализациялау

Айнымалы мәндерді инициализациялау Java тіліндегі ең қиын тақырыптардың бірі болып табылады, себебі... жадпен жұмыс істеу, JVM енгізу, JVM спецификациясы және басқа да қорқынышты және қиын нәрселермен өте тығыз байланысты. Бірақ сіз оны кем дегенде белгілі бір дәрежеде анықтауға тырыса аласыз. Қарапайымнан күрделіге көшейік. Айнымалы мәнді инициализациялау үшін біз тағайындау операторын қолданамыз және алдыңғы codeтағы жолды өзгертеміз:
int number = 2;
Бұл опцияда қателер болмайды және мән экранда көрсетіледі. Бұл жағдайда не болады? Дәлелдеуге тырысайық. Егер айнымалыға мән тағайындағымыз келсе, онда бұл айнымалы мәнді сақтауын қалаймыз. Мәнді бір жерде сақтау керек екен, бірақ қайда? Дискіде ме? Бірақ бұл өте баяу және бізге шектеулер қоюы мүмкін. Деректерді «осында және қазір» тез және тиімді сақтай алатын жалғыз орын - жад. Бұл жадта біраз орын бөлу керек дегенді білдіреді. Дәл солай. Айнымалы инициализацияланған кезде, оған біздің бағдарлама орындалатын java процесіне бөлінген жадта бос орын бөлінеді. Java процесіне бөлінген жад бірнеше аймақтарға немесе аймақтарға бөлінеді. Олардың қайсысы кеңістікті бөлетіні айнымалының қай типке жарияланғанына байланысты. Жад келесі бөлімдерге бөлінеді: үйме, стек және үйме емес . Стек жадынан бастайық. Стек стек деп аударылады (мысалы, кітаптар жинағы). Бұл LIFO (соңғы кіріс, бірінші шығыс) деректер құрылымы. Яғни, бір топ кітап сияқты. Біз оған кітаптарды қосқанда, біз оларды үстіне қоямыз, ал оларды алып тастағанда, біз ең жоғарғысын аламыз (яғни, ең соңғы қосылған). Сонымен, біз бағдарламамызды бастаймыз. Біз білетіндей, Java бағдарламасын JVM, яғни Java виртуалды машинасы орындайды. JVM бағдарламаны орындау қай жерде басталуы керек екенін білуі керек. Ол үшін біз «кіру нүктесі» деп аталатын негізгі әдісті жариялаймыз. JVM жүйесінде орындау үшін негізгі ағын (Thread) жасалады. Жіп жасалғанда, ол жадта өзінің стекін бөледі. Бұл стек кадрлардан тұрады. Әрбір жаңа әдіс ағында орындалғанда, оған жаңа жақтау бөлініп, стектің жоғарғы жағына қосылады (кітаптар дестеіндегі жаңа кітап сияқты). Бұл жақтауда нысандарға және қарабайыр түрлерге сілтемелер болады. Иә, иә, біздің int стекке сақталады, себебі... int - қарабайыр тип. Фреймді бөлмес бұрын JVM онда не сақтау керектігін түсінуі керек. Дәл осы себепті біз «айнымалы инициализацияланбаған болуы мүмкін» қатесін аламыз, себебі ол инициализацияланбаған болса, JVM біз үшін стек дайындай алмайды. Сондықтан, бағдарламаны құрастырған кезде, смарт компилятор қателіктер жібермеуге және бәрін бұзуға көмектеседі. (!) Түсінікті болу үшін мен өте жақсы мақаланы ұсынамын: “ Java стек және үйіндісі: Java жадын бөлу оқулығы ”. Ол бірдей керемет бейнеге сілтеме жасайды:
Әдістің орындалуы аяқталғаннан кейін осы әдістерге бөлінген фреймдер ағынның стекінен жойылады және олармен бірге барлық деректермен осы кадрға бөлінген жады тазаланады.

Жергілікті нысан айнымалыларын инициализациялау

Кодымызды қайтадан күрделірек етіп өзгертейік:
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 типі. Ал стек үймедегі нысанға сілтемені ғана сақтайды (біз бұл нысанға қандай да бір жолмен қол жеткізуіміз керек). Әрі қарай, негізгі әдіс стекінде println әдісін орындау үшін кадрлар бөлінеді. Негізгі әдісті орындағаннан кейін барлық кадрлар жойылады. Егер кадр жойылса, барлық деректер жойылады. Нысан an objectісі бірден жойылмайды. Біріншіден, оған сілтеме жойылады және осылайша енді ешкім an object нысанына сілтеме жасамайды және жадтағы бұл нысанға қол жеткізу мүмкін болмайды. Ақылды JVM-де бұл үшін өз механизмі бар - қоқыс жинағыш (қоқыс жинағыш немесе қысқаша GC). Содан кейін ол ешкім сілтеме жасамайтын an objectілерді жадтан жояды. Бұл процесс жоғарыда келтірілген сілтемеде қайтадан сипатталған. Түсініктемесі бар видео да бар.

Өрістерді инициализациялау

Класста көрсетілген өрістерді инициализациялау өрістің статикалық немесе статикалық еместігіне байланысты ерекше жолмен жүреді. Егер өрісте static түйінді сөзі болса, онда бұл өріс сыныптың өзіне сілтеме жасайды, ал егер 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 сынып нысаны жасалғаннан кейін инициализацияланады. Бірақ сынып Java виртуалды машинасымен жүктелген кезде санау өрісі инициализацияланады. Сабақты жүктеу - бұл бөлек тақырып, сондықтан біз оны мұнда араластырмаймыз. Класс орындалу уақытында белгілі болған кезде статикалық айнымалылар инициализацияланғанын білу керек. Бұл жерде тағы бір нәрсе маңыздырақ және сіз мұны байқадыңыз. Мәнді еш жерде көрсетпедік, бірақ ол жұмыс істейді. Және шынымен де. Өріс болып табылатын айнымалылар, егер оларда көрсетілген мән болмаса, олар әдепкі мәнмен инициализацияланады. Сандық мәндер үшін бұл өзгермелі нүктелі сандар үшін 0 немесе 0,0. Логикалық үшін бұл жалған. Және барлық нысан түрінің айнымалылары үшін мән бос болады (бұл туралы кейінірек айтатын боламыз). Неліктен бұлай болған сияқты? Бірақ нысандар үймеде (үймеде) жасалғандықтан. Бұл аймақпен жұмыс Runtime бағдарламасында орындалады. Және біз бұл айнымалы мәндерді орындау уақытында инициализациялай аламыз, стекке қарағанда, жады орындау алдында дайындалуы керек. Java тілінде жад осылай жұмыс істейді. Бірақ бұл жерде тағы бір ерекшелік бар. Бұл кішкене бөлік жадтың әртүрлі бұрыштарына әсер етеді. Біздің есімізде, негізгі әдіс үшін Стек жадында кадр бөлінген. Бұл жақтау үйме жадындағы нысанға сілтемені сақтайды. Бірақ онда санау қайда сақталады? Естеріңізде болса, бұл айнымалы нысан үймеде жасалмас бұрын бірден инициализацияланады. Бұл шынымен қиын сұрақ. 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);
    }

}

Нөл деген не

Жоғарыда айтылғандай, нысан түрлерінің айнымалылары, егер олар сыныптың өрістері болса, әдепкі мәндерге инициализацияланады және бұл әдепкі мән бос болады. Бірақ Java-да нөл деген не? Есте сақтау керек бірінші нәрсе - қарабайыр типтер нөл болуы мүмкін емес. Өйткені null - бұл еш жерде, кез келген нысанға сілтеме жасамайтын арнайы сілтеме. Сондықтан тек 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