{
  "assessmentTests": {
    "java_test": {
      "name": "Java тесті",
      "desc": "Негізгі синтаксис, ООП механикасы, коллекциялар, дженериктер, ерекше жағдайлар және параллельді бағдарламалау бойынша 30 сценарийлік сұрақ — Java біліміңіз жұмыс хабарландыруларындағы «Java меңгеру» талабына сай келе ме, соны анықтаңыз.",
      "recommendation": "Сіздің Java дағдыларыңыздың профилі",
      "results": {
        "beginner": {
          "name": "Бастауыш деңгей",
          "desc": "Сіз жұмыс істейтін сыныптар мен әдістерді жаза аласыз, бірақ қателескен сұрақтарыңыз синтаксиске емес, негізінен сәйкестік пен әдепкі мәндерге қатысты — екі String объектісін == арқылы салыстыру мен .equals арасындағы айырмашылық, неге new String(\"x\") жол пулын (string pool) ешқашан қайта пайдаланбайтыны, сан өрісінің әдепкі мәні орамдық (wrapper) өрістен қалай ерекшеленетіні. Бұның бәрі Java-ны нашар білу дегенді білдірмейді; бұл тілді сілтемелер мен қарапайым типтердің астарында нақты қалай жұмыс істейтінінен емес, сынақ пен қателік арқылы үйренген адамдарды әдетте шатастыратын нақты ережелер. Олар жұмыста маңызды, өйткені әр жағдайда код компиляциядан өтеді, іске қосылады және байқаусызда қате нәрсе істейді.",
          "recommendation": "Үш нәрседен осы ретпен бастаңыз: неге екі String объектісін == арқылы салыстырғанда таңбалар емес, сілтемелер салыстырылады (ал .equals дерлік әрқашан сізге керегі), int асып кетуі (overflow) неге қате лақтырмай, үнсіз айналып кетеді, және неге инициализацияланбаған Integer өрісі null-ге, ал int өрісі 0-ге әдепкі бойынша тең болады. Oracle-дың ресми Java оқулықтары мен Baeldung екеуі де осы үшеуін де іске қосуға болатын мысалдармен түсіндіреді."
        },
        "intermediate": {
          "name": "Орта деңгей",
          "desc": "Сіз күнделікті қолданба кодын еркін меңгергенсіз — сыныптар, коллекциялар, қарапайым басқару ағыны (control flow) — және әдеттегі функционалдық жұмыс сізді қиналтпайды. Осы деңгей мен «Жетілдірілген» деңгей арасындағы алшақтық негізінен Java ережелері параллельдікпен және дженериктермен әрекеттескенде не болатынына байланысты: static әдіс сіз күткен объект бойынша емес, жарияланған тип бойынша шешіледі, HashMap-тың итерация ретіне байқаусызда сеніп қалу, циклдің ортасында элементті алып тастағаннан туындайтын ConcurrentModificationException. Мұндай қателер тез көзбен тексергенде байқалмайды және тек белгілі бір орындалу жағдайында ғана көрінеді.",
          "recommendation": "Компилятордың кодыңызды статикалық тұрғыдан қалай көретіні мен оның нақты қалай орындалатыны арасындағы айырмашылыққа назар аударыңыз: орамдау (overload) шешімі мен static әдістің жасырылуы нақты объект типі емес, жарияланған тип бойынша анықталады, HashMap неге итерация ретіне ешқандай кепілдік бермейтіні, және тізімді итерациялап жатқанда тікелей өзгерту неге ConcurrentModificationException лақтыратыны. Содан кейін дженериктердің erasure механизмін қараңыз, өйткені бұл коллекцияларды жеке-жеке білетін адамдарды да шатастырады."
        },
        "advanced": {
          "name": "Жетілдірілген деңгей",
          "desc": "Бұл көптеген жұмыс хабарландыруларында «күшті Java» деп аталатын деңгей. Сіз static блоктары, instance блоктары және бірнеше конструкторы бар сыныпты оқып, олардың нақты қай ретпен орындалатынын болжай аласыз, finally блогының try блогының қайтарылатын мәнін байқаусызда қалай жоятынын білесіз, және қолмен finally-close жасаудың орнына try-with-resources қолданасыз, өйткені ол беретін реттілік кепілдігін білесіз. Бұл деңгейді ең жоғарғысынан бөлетін — жұмыстың параллельді және интерфейс деңгейіндегі жағы: synchronized нақты нені құлыптайтыны, volatile нені кепілдендіріп, нені кепілдендірмейтіні, және default-әдіс қайшылықтары қалай шешілетіні.",
          "recommendation": "Басқа ағындар мен басқа интерфейстер де қатынасатын кодты қорғайтын бөліктерге тереңдей түсіңіз: synchronized instance әдісі мен synchronized static әдісі нені құлыптайтынының айырмашылығы, volatile неге көріну (visibility) береді, бірақ counter++ үшін атомарлылық бермейтіні, және Java default-әдіс «алмас» (diamond) қайшылығын қолмен шешуге қалай мәжбүрлейтіні. Java Memory Model бойынша Baeldung мен Java Concurrency in Practice материалдары екеуі үшін де табиғи келесі қадам болады."
        },
        "expert": {
          "name": "Сарапшы деңгейі",
          "desc": "Сіз әр бөлімде ең жоғары нәтиже көрсеттіңіз — негізгі синтаксис пен типтер, ООП механикасы мен ауқымы (scope), коллекциялар мен дженериктер, сондай-ақ ерекше жағдайлар, параллельділік және идиомалар. Іс жүзінде бұл — сізге бөтен адамның сыныбын берсе, ол неге компиляция қатесі, runtime ерекше жағдайы немесе байқаусызда қате мән беретінін, тек синтаксис бойынша не істеуі керегін емес, түсіндіре аласыз дегенді білдіреді, ал бұл әлдеқайда қиын әрі құндырақ дағды. Бұл деңгейде тілдің өзі сирек шектеуші фактор болады; шектеу әдетте параллельділік дизайнында немесе астындағы деректердің құрылымында болады.",
          "recommendation": "Енді нәтиже дизайн мен диагностикада: тоқтап қалуды бірден deadlock деп есептеместен бұрын thread dump-ты оқу, synchronized, java.util.concurrent құлыптары мен атомарлық операциялар арасында әдепкі таңдау емес, сараланған ымыра ретінде таңдау жасау, және stream-конвейерін әдейі, байқаусызда емес, «жалқау» (lazy) күйінде қалдыратын дизайн жасау. Егер сізді лауазымға сынап жатса, Java мүмкіндіктерінің атын атаудың орнына, продакшннан тапқан concurrency қатесін — мысалы, жіберіп алған happens-before шекарасын немесе ConcurrentModificationException жағдайын — сипаттаңыз, бұл тек терминологияны емес, ойлау логикасын көрсетеді."
        }
      },
      "questions": [
        {
          "question": "Сіз екі String объектісін жасайсыз: String a = new String(\"cat\"); String b = new String(\"cat\"); a == b нені қайтарады?",
          "options": [
            {
              "icon": "",
              "label": "true — бірдей таңбалары бар String литералдары әрқашан бір объект болып табылады"
            },
            {
              "icon": "",
              "label": "true — new String(...) жол пулын (string pool) қайта пайдаланады, сондықтан бірдей мәтін әрқашан бір объектіні ортақ пайдаланады"
            },
            {
              "icon": "",
              "label": "Компиляция қатесі — == операторын String объектілерін салыстыру үшін пайдалануға болмайды"
            },
            {
              "icon": "",
              "label": "false — new String(...) әрқашан үйіндіде (heap) жаңа объект бөледі, сондықтан == екі түрлі сілтемені салыстырады, дегенмен .equals(b) true қайтарар еді"
            }
          ]
        },
        {
          "question": "Integer x = 100; Integer y = 100; System.out.println(x == y); содан Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); Бұл екі жол нені шығарады?",
          "options": [
            {
              "icon": "",
              "label": "true, содан true — автобокстелген (autoboxed) Integer объектілері мәніне қарамастан әрқашан кэштеледі"
            },
            {
              "icon": "",
              "label": "false, содан false — Integer объектілеріндегі == әрқашан сілтемелерді салыстырады, сондықтан тең мәндер ешқашан сәйкес келмейді"
            },
            {
              "icon": "",
              "label": "true, содан false, бірақ бұл тек 200 санының байт шегінен асып кетуіне байланысты — кэш шекарасының -128..127 аралығына қатысы жоқ"
            },
            {
              "icon": "",
              "label": "true, содан false — -128-ден 127-ге дейінгі автобокстелген Integer мәндері кэштеліп, ортақ пайдаланылады, сондықтан 100 бір объектіні қайта пайдаланады, ал 200 кэш ауқымынан шығып, екі бөлек объектіге автобокстеледі"
            }
          ]
        },
        {
          "question": "int max = Integer.MAX_VALUE; System.out.println(max + 1); Не болады?",
          "options": [
            {
              "icon": "",
              "label": "Ол бүтін сан асып кетуі (integer overflow) үшін ArithmeticException лақтырады"
            },
            {
              "icon": "",
              "label": "Ол қайтадан Integer.MAX_VALUE шығарады, себебі Java типтің максимум мәнінде тоқтатып қояды"
            },
            {
              "icon": "",
              "label": "Ол Integer.MIN_VALUE шығарады — int арифметикасы асып кеткенде қате лақтырмай, үнсіз айналып өтеді"
            },
            {
              "icon": "",
              "label": "Бұл компиляция қатесі — компилятор асып кетуді алдын ала анықтайды"
            }
          ]
        },
        {
          "question": "System.out.println(0.1 + 0.2 == 0.3); Бұл нені шығарады, және неге?",
          "options": [
            {
              "icon": "",
              "label": "false — 0.1, 0.2 және 0.3 сандарын екілік жылжымалы үтірмен (binary floating point) дәл көрсету мүмкін емес, сондықтан қосынды дөңгелектеу қатесін алып жүреді де, ол 0.3-ке бит-биттеп тең болмай шығады"
            },
            {
              "icon": "",
              "label": "true — Java double арифметикасын салыстырмас бұрын жақын ондық мәнге дейін дөңгелектейді"
            },
            {
              "icon": "",
              "label": "true — екі ондық таңбасы бар мәндер үшін екі double қосындысы әрқашан дәл болады"
            },
            {
              "icon": "",
              "label": "Ол ерекше жағдай лақтырады, себебі Java-да double үшін == анықталмаған"
            }
          ]
        },
        {
          "question": "Сынып инициализаторсыз екі instance өрісін жариялайды: int count; және Integer total; Конструктор орындалмас бұрын олардың әдепкі мәндері қандай?",
          "options": [
            {
              "icon": "",
              "label": "Екеуі де 0-ге әдепкі бойынша тең болады, себебі Integer өріс инициализациясында int-ке автобокстеледі"
            },
            {
              "icon": "",
              "label": "count 0-ге, total 0-ге тең, ол алғаш оқылғанда автоматты түрде бокстеледі"
            },
            {
              "icon": "",
              "label": "count 0-ге, total null-ге тең — примитивті сан өрістері әдепкі бойынша нөлге тең болады, ал инициализацияланбаған орамдық (wrapper) сілтеме өрісі кез келген басқа объект сілтемесі сияқты null-ге тең болады"
            },
            {
              "icon": "",
              "label": "Екеуі де айқын мән берілгенше null-ге тең болады, себебі Java-да жасырын сандық әдепкі мәндер жоқ"
            }
          ]
        },
        {
          "question": "Цикл 1000 рет орындалады, әр итерацияда String result айнымалысына result += \"x\"; жасайды. Әр итерацияда іс жүзінде не болады?",
          "options": [
            {
              "icon": "",
              "label": "Бар String объектісінің ішкі таңбалар массиві сол орында ұзартылады"
            },
            {
              "icon": "",
              "label": "Java біріктірулерді автоматты түрде топтап, тек соңғы бір String объектісін ғана бөледі"
            },
            {
              "icon": "",
              "label": "Бұл барлық 1000 итерацияға ортақ бір StringBuilder.append() шақыруына компиляцияланады, әр итерацияда қосымша объект бөлінбейді"
            },
            {
              "icon": "",
              "label": "Мүлдем жаңа String объектісі жасалады да, result соған қайта меңзейді — алдыңғы String объектісі тасталады, себебі String өзгермейтін (immutable) және += оны сол орында өзгерте алмайды"
            }
          ]
        },
        {
          "question": "final List<String> names = new ArrayList<>(); Мыналардың қайсысы дұрыс?",
          "options": [
            {
              "icon": "",
              "label": "names.add(\"Ana\") компиляциядан өтеді және дұрыс жұмыс істейді — final тек names сілтемесінің өзін қайта тағайындауға тыйым салады, ол меңзеп тұрған объектіні өзгертуге емес"
            },
            {
              "icon": "",
              "label": "names.add(\"Ana\") компиляция қатесі болады, себебі final тізімнің өзін өзгертілмейтін етеді"
            },
            {
              "icon": "",
              "label": "Бұл тізім параллельді жазу үшін қауіпсіз (thread-safe), себебі ол final деп жарияланған"
            },
            {
              "icon": "",
              "label": "Локал айнымалыдағы final ешқандай әсер етпейді, тек тип те өзгермейтін деп жарияланса ғана"
            }
          ]
        },
        {
          "question": "int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); System.out.println(Arrays.equals(a, b)); Бұл екі жол нені шығарады?",
          "options": [
            {
              "icon": "",
              "label": "false, содан true — == массив сілтемелерін салыстырады (екі түрлі массив объектісі), ал Arrays.equals элементтерді салыстырады"
            },
            {
              "icon": "",
              "label": "true, содан true — мазмұны бірдей массивтер Java-да бір объект болып табылады"
            },
            {
              "icon": "",
              "label": "false, содан false — Arrays.equals тек объект массивтері үшін ғана жұмыс істейді, примитивті int массивтері үшін емес"
            },
            {
              "icon": "",
              "label": "true, содан false — массивтердегі == мазмұнды салыстырады, ал Arrays.equals артық"
            }
          ]
        },
        {
          "question": "void show(Object o) { print(\"Object\"); } void show(String s) { print(\"String\"); } Object ref = \"hello\"; show(ref); Қай орамдау (overload) орындалады, және неге?",
          "options": [
            {
              "icon": "",
              "label": "show(String) орындалады, себебі Java орамдауды таңдамас бұрын объектінің нақты runtime класын тексереді"
            },
            {
              "icon": "",
              "label": "show(Object) орындалады — орамдауды таңдау компиляция кезінде айнымалының жарияланған типі бойынша шешіледі, ол меңзеп тұрған объектінің нақты runtime типі бойынша емес"
            },
            {
              "icon": "",
              "label": "Бұл компиляция қатесі — нақтырақ орамдау бар жерде Object типін беруге болмайды"
            },
            {
              "icon": "",
              "label": "Екі әдіс те бір-бірден орындалады, себебі Java орамдауды әрбір сәйкестікті байқап көру арқылы шешеді"
            }
          ]
        },
        {
          "question": "Base сыныбында static void greet() { print(\"Base\"); } бар. Derived сыныбы Base-тен мұрагерленеді және өз алдына static void greet() { print(\"Derived\"); } жариялайды. Сіз мынаны жазасыз: Base ref = new Derived(); ref.greet(); Не басылады?",
          "options": [
            {
              "icon": "",
              "label": "Derived — static әдістер instance әдістер сияқты override болады, объектінің нақты runtime типіне сай"
            },
            {
              "icon": "",
              "label": "Бұл компиляция қатесі — static әдістерді instance сілтемесі арқылы шақыруға болмайды"
            },
            {
              "icon": "",
              "label": "Base — static әдістер полиморфты емес; оны сілтеме арқылы шақыру компиляция кезінде сілтеменің жарияланған типі бойынша шешіледі, объектінің нақты типі бойынша емес"
            },
            {
              "icon": "",
              "label": "Base де, Derived де басылады, себебі шақыру жасырылған және жасырушы нұсқалардың екеуіне де шешіледі"
            }
          ]
        },
        {
          "question": "Әдіс ішінде int count = 0; деп жазасыз, содан кейін басқа әдіске берілетін lambda ішінен count-ты пайдаланғыңыз келеді. Бұл компиляциядан өту үшін count туралы не рас болуы керек?",
          "options": [
            {
              "icon": "",
              "label": "count іс жүзінде final (effectively final) болуы керек — бастапқы мәнінен кейін ешқашан қайта тағайындалмауы керек — себебі lambda өзгеретін локал айнымалыға тірі сілтемені емес, оның бір сәттегі көшірмесін алады"
            },
            {
              "icon": "",
              "label": "Ешнәрсе талап етілмейді — кез келген локал айнымалыны lambda ішінен еркін оқуға және қайта тағайындауға болады"
            },
            {
              "icon": "",
              "label": "count volatile деп жариялануы керек, сонда lambda оның ең соңғы мәнін әрқашан көреді"
            },
            {
              "icon": "",
              "label": "count локал айнымалы емес, өріс болуы керек — lambda локал айнымалыларды мүлдем ала алмайды"
            }
          ]
        },
        {
          "question": "void rename(StringBuilder sb) { sb = new StringBuilder(\"new\"); } әдісі мына түрде шақырылады: StringBuilder original = new StringBuilder(\"old\"); rename(original); Шақырудан кейін original неге тең?",
          "options": [
            {
              "icon": "",
              "label": "\"new\"-ге тең болады — Java-да объектілер сілтеме бойынша беріледі, сондықтан параметрді қайта тағайындау шақырушының айнымалысын да өзгертеді"
            },
            {
              "icon": "",
              "label": "Тек StringBuilder сияқты өзгермелі (mutable) типтер үшін ғана \"new\"-ге тең болады, өзгермейтін (immutable) типтер үшін емес"
            },
            {
              "icon": "",
              "label": "Әлі де \"old\" — Java сілтеменің өзін мән бойынша (by value) береді, сондықтан әдіс ішінде параметрді қайта тағайындау тек сілтеменің локал көшірмесін қайта бағыттайды, ал шақырушының original айнымалысы өзгеріссіз қалады"
            },
            {
              "icon": "",
              "label": "Runtime кезінде ерекше жағдай лақтырады, себебі sb әдіс ішінде қайта тағайындалды"
            }
          ]
        },
        {
          "question": "Сыныпта static initializer блогы, instance initializer блогы және конструктор бар, дәл осы ретпен жазылған. Сіз осы сыныптың екі объектісін бірінен соң бірін жасайсыз. Бұлар қай ретпен орындалады?",
          "options": [
            {
              "icon": "",
              "label": "static блок дәл бір рет, сынып алғаш жүктелгенде орындалады; содан кейін әр объект үшін instance блогы, содан соң конструктор денесі орындалады"
            },
            {
              "icon": "",
              "label": "Үшеуі де жасалған әрбір объект үшін бастапқы код ретімен қайтадан орындалады"
            },
            {
              "icon": "",
              "label": "Әр объект үшін алдымен конструктор, содан instance блогы, соңында бір рет static блок орындалады"
            },
            {
              "icon": "",
              "label": "static блок әр объект үшін бір рет, instance блогынан дәл алдында орындалады"
            }
          ]
        },
        {
          "question": "Сыныпта void log(String s) және void log(String... args) бар. Сіз log(\"hi\") деп шақырасыз. Қайсысы орындалады?",
          "options": [
            {
              "icon": "",
              "label": "log(String... args) — varargs орамдауы екеуі де сәйкес келгенде әрқашан артық көрінеді"
            },
            {
              "icon": "",
              "label": "Бұл компиляция қатесі — шақыру екі орамдаудың арасында екіұшты"
            },
            {
              "icon": "",
              "label": "log(String s) — бекітілген параметр саны бар орамдау дәл сәйкес келгенде, Java оны әрқашан varargs орамдауынан артық көреді; varargs тек соңғы амал ретінде ғана қолданылады"
            },
            {
              "icon": "",
              "label": "Файлда бірінші жарияланғаны орындалады"
            }
          ]
        },
        {
          "question": "Конструктордың бірінші жолы бір сыныптағы басқа конструкторға тапсыру үшін this(0); шақырады. Бұл қай жерде орналасуға рұқсат етілген?",
          "options": [
            {
              "icon": "",
              "label": "Конструктор денесінің кез келген жерінде, объект қайтарылмас бұрын орындалса болғаны"
            },
            {
              "icon": "",
              "label": "Тек конструктордың дәл бірінші операторы ретінде — this() (немесе super()) бірінші жол болуы керек, әрі конструктор this() мен super() екеуін де шақыра алмайды"
            },
            {
              "icon": "",
              "label": "Тек соңғы оператор ретінде, барлық өрістердің инициализациясы аяқталғаннан кейін"
            },
            {
              "icon": "",
              "label": "Тек delegate кілт сөзімен айқын белгіленген конструкторларда ғана"
            }
          ]
        },
        {
          "question": "Сізге алдыңғы жағына элементтер өте жиі қосылатын, ал кездейсоқ қатынау арқылы оқу сирек болатын тізім керек. Құрылымдық тұрғыдан қайсысы жақсырақ сәйкес келеді, және неге?",
          "options": [
            {
              "icon": "",
              "label": "ArrayList — оның тұтас (contiguous) ішкі массиві барлық операцияны, оның ішінде алдыңғы жаққа қосуды да, байланысты құрылымнан тезірек етеді"
            },
            {
              "icon": "",
              "label": "Екеуі де бірдей жұмыс істейді, себебі екеуі де List интерфейсін бірдей уақыт кепілдіктерімен іске асырады"
            },
            {
              "icon": "",
              "label": "LinkedList — алдыңғы жаққа қосу O(1), себебі бұл тек бір түйінді қайта байланыстырады, ал ArrayList бар элементтердің бәрін бір позицияға жылжытуы керек, сондықтан алдыңғы жаққа қосу O(n) болады"
            },
            {
              "icon": "",
              "label": "LinkedList, себебі ол кездейсоқ қатынауды O(1) уақытында қолдайды, ал ArrayList қолдамайды"
            }
          ]
        },
        {
          "question": "Сіз қарапайым HashMap-қа белгілі бір ретпен бес жазба енгізесіз, содан кейін оны for-each циклімен аралайсыз. Жазбалар қандай ретпен шығады?",
          "options": [
            {
              "icon": "",
              "label": "Жазбалар енгізілген дәл сол ретпен, себебі Java карталары әрқашан енгізу ретін сақтайды"
            },
            {
              "icon": "",
              "label": "Ешқандай кепілді рет жоқ — HashMap-тың итерация реті hash-корзинаға (hash bucket) орналасуына байланысты, енгізу ретіне емес, тіпті әр іске қосу арасында өзгеруі мүмкін; енгізу ретін сақтайтын — LinkedHashMap"
            },
            {
              "icon": "",
              "label": "Кілт бойынша автоматты түрде сұрыпталған, TreeMap сияқты"
            },
            {
              "icon": "",
              "label": "Енгізу ретіне кері, себебі HashMap ішінде стек пайдаланады"
            }
          ]
        },
        {
          "question": "Қарапайым java.util.HashMap бір мезгілде қанша null кілт және қанша null мән сақтай алады?",
          "options": [
            {
              "icon": "",
              "label": "Ешбір Map іске асырылымында null кілттер де, null мәндер де ешқашан рұқсат етілмейді"
            },
            {
              "icon": "",
              "label": "Ең көбі бір null кілт және кез келген санда null мән — HashMap бір ғана null кілтке рұқсат етеді, ал Hashtable екеуін де рұқсат етпейді"
            },
            {
              "icon": "",
              "label": "Шексіз null кілт және шексіз null мән, себебі null кез келген басқа кілт сияқты қарастырылады"
            },
            {
              "icon": "",
              "label": "Ең көбі бір null кілт және бір null мән, екеуі де бірмен шектелген"
            }
          ]
        },
        {
          "question": "Сіз List-ті for-each циклімен аралап, цикл денесінің ішінен list.remove(item) шақырасыз — барлық емес, кейбір элементтер үшін ғана. Не болады?",
          "options": [
            {
              "icon": "",
              "label": "Ол дұрыс жұмыс істейді және дәл ойлаған элементтерді алып тастайды"
            },
            {
              "icon": "",
              "label": "Ол алынып тасталған элементтен кейінгі элементті үнсіз өткізіп жібереді, бірақ басқа жағынан қатесіз аяқталады"
            },
            {
              "icon": "",
              "label": "Цикл тізімнің ескі өлшеміне жеткенде IndexOutOfBoundsException лақтырады"
            },
            {
              "icon": "",
              "label": "Ол ConcurrentModificationException лақтырады — жасырын iterator тізімді аралап жатқанда оның құрылымын тікелей өзгерту байқалып, қабылданбайды; оның орнына Iterator.remove() қолданылуы керек"
            }
          ]
        },
        {
          "question": "Runtime кезінде List<String> list берілгенде, оның дженерик тип параметрі туралы reflection немесе instanceof арқылы іс жүзінде не анықтауға болады?",
          "options": [
            {
              "icon": "",
              "label": "Runtime кезінде String.class алу үшін list.getElementType() шақыруға болады"
            },
            {
              "icon": "",
              "label": "instanceof List<String> компиляциядан өтеді және элемент типін дұрыс тексереді"
            },
            {
              "icon": "",
              "label": "JVM тип параметрін list.getGenericType() арқылы қолжетімді жасырын метадеректер ретінде сақтайды"
            },
            {
              "icon": "",
              "label": "Ешнәрсе — дженерик тип туралы ақпарат компиляция кезінде өшіріледі (erasure), сондықтан runtime кезінде объект жай ғана List, әрі оның List<String> немесе List<Integer> болып жарияланғанын қалпына келтірудің жолы жоқ"
            }
          ]
        },
        {
          "question": "switch (day) { case 1: case 2: print(\"Weekday\"); break; case 6: print(\"Saturday\"); case 7: print(\"Sunday\"); break; default: print(\"?\"); } Егер day 6-ға тең болса, не басылады?",
          "options": [
            {
              "icon": "",
              "label": "Тек Saturday — switch-тегі әрбір case блогы өз print операторынан кейін әрқашан тоқтайды"
            },
            {
              "icon": "",
              "label": "Тек Sunday — сәйкестік case 6-дан басталады, бірақ break-тен алдыңғы тек соңғы сәйкес келетін белгі ғана орындалады"
            },
            {
              "icon": "",
              "label": "Ештеңе басылмайды, себебі day 6-ға тікелей өз break-і бар сәйкес case жоқ"
            },
            {
              "icon": "",
              "label": "Saturday, содан Sunday — case 6-да break жоқ, сондықтан орындалу келесі break-ке жеткенше кезекті case кодына түсіп кетеді (fall through)"
            }
          ]
        },
        {
          "question": "Product сыныбына баға бойынша жалғыз, айқын «табиғи» сұрыптау реті керек, әрі кодтың басқа жерлерінде атау немесе қор деңгейі бойынша да сұрыптау мүмкіндігі керек. Қай комбинация дұрыс дизайн болады?",
          "options": [
            {
              "icon": "",
              "label": "Comparable<Product> интерфейсін әр реттеу үшін бөлек-бөлек үш рет іске асыру керек, ал шақырушы қай compareTo орындалатынын өзі таңдасын"
            },
            {
              "icon": "",
              "label": "Табиғи баға реті үшін Comparable<Product> интерфейсін іске асырып, ал басқа жерлерде қолданылатын атау мен қор деңгейі реттері үшін бөлек Comparator<Product> мысалдарын жазу керек"
            },
            {
              "icon": "",
              "label": "Баға да қосқанда, барлық реттеу үшін тек Comparator қолдану керек, себебі мұнда Comparable-дың артықшылығы жоқ"
            },
            {
              "icon": "",
              "label": "Тек Comparable қолданып, әр реттеу үшін бір-бірден үш орамдалған compareTo әдісін қосу керек"
            }
          ]
        },
        {
          "question": "Әдіс new FileReader(path) шақырады, ол throws IOException деп жарияланған. IOException — Exception-нан мұрагерленеді, RuntimeException-нан емес. Бұл компиляциядан өту үшін не істеу керек?",
          "options": [
            {
              "icon": "",
              "label": "Ештеңе істеудің қажеті жоқ — компилятор мұны тек RuntimeException-нан мұрагерленетін ерекше жағдайлар үшін ғана талап етеді"
            },
            {
              "icon": "",
              "label": "IOException-ды try/catch ішінде ұстау керек немесе өз әдісіңізде throws IOException деп жариялау керек — тексерілетін (checked) ерекше жағдайлар айқын түрде өңделуі немесе таратылуы керек, тексерілмейтін (unchecked) RuntimeException ұрпақтарынан айырмашылығы осында"
            },
            {
              "icon": "",
              "label": "Шақыруды RuntimeException үшін try/catch ішіне орау керек, себебі заманауи Java-да IOException автоматты түрде тексерілмейтін болады"
            },
            {
              "icon": "",
              "label": "Әдісті static деп жариялау керек — static әдістер тексерілетін ерекше жағдайларды өңдеуден босатылған"
            }
          ]
        },
        {
          "question": "try (Resource a = new Resource(\"A\"); Resource b = new Resource(\"B\")) { ... } AutoCloseable интерфейсін іске асыратын екі ресурсты пайдаланады. Егер try блогы қалыпты аяқталса, олар қай ретпен жабылады?",
          "options": [
            {
              "icon": "",
              "label": "Алдымен A жабылады, содан B — жариялау ретіне сай"
            },
            {
              "icon": "",
              "label": "Алдымен B жабылады, содан A — try-with-resources ресурстарды жариялау ретіне кері ретпен жабады"
            },
            {
              "icon": "",
              "label": "Екеуі де бір мезгілде жабылады, себебі try-with-resources тазалауды параллельдейді"
            },
            {
              "icon": "",
              "label": "Тек B ғана автоматты түрде жабылады — A-ны finally блогында әлі де қолмен жабу керек"
            }
          ]
        },
        {
          "question": "int getValue() { try { return 1; } finally { return 2; } } getValue() шақырғанда не қайтарылады?",
          "options": [
            {
              "icon": "",
              "label": "1 — try блогының қайтарылатын мәні finally орындалмас бұрын әлдеқашан бекітілген, сондықтан finally оны өзгерте алмайды"
            },
            {
              "icon": "",
              "label": "Ол runtime кезінде ерекше жағдай лақтырады, себебі әдіс екі жерден қайтара алмайды"
            },
            {
              "icon": "",
              "label": "2 — finally ішіндегі return операторы try блогынан келе жатқан кез келген return-ды үстінен басып, оны алмастырады да, 1 мәнін толығымен тастап кетеді"
            },
            {
              "icon": "",
              "label": "Бұл компиляция қатесі — finally ішінде return операторы болуға рұқсат етілмейді"
            }
          ]
        },
        {
          "question": "try { ... } catch (IOException e) { ... } catch (FileNotFoundException e) { ... }, ал FileNotFoundException IOException-нан мұрагерленеді. Мұны компиляциялауға тырысқанда не болады?",
          "options": [
            {
              "icon": "",
              "label": "Компиляция қатесі — FileNotFoundException catch блогына қол жеткізу мүмкін емес, себебі алдыңғы, жалпырақ IOException catch блогы кез келген FileNotFoundException-мен әлдеқашан сәйкес келеді"
            },
            {
              "icon": "",
              "label": "Ол дұрыс компиляцияланады, әрі дәл осы тип лақтырылғанда нақтырақ FileNotFoundException блогы орындалады"
            },
            {
              "icon": "",
              "label": "Ол дұрыс компиляцияланады, әрі FileNotFoundException үшін екі catch блогы да ретімен орындалады"
            },
            {
              "icon": "",
              "label": "Компиляция кезінде дұрыс, бірақ FileNotFoundException нақты алғаш пайда болғанда runtime қатесін лақтырады"
            }
          ]
        },
        {
          "question": "Сыныпта synchronized instance әдісі process() және synchronized static әдісі configure() бар. Әрқайсысы нақты нені құлыптайды?",
          "options": [
            {
              "icon": "",
              "label": "process() ол шақырылған нақты объект мысалының мониторын құлыптайды, ал configure() Class объектісінің өз мониторын құлыптайды — бұл әрбір мысалға ортақ"
            },
            {
              "icon": "",
              "label": "Екеуі де мысалға немесе сыныпқа қарамастан бүкіл JVM үшін бір ғана ортақ құлыпты құлыптайды"
            },
            {
              "icon": "",
              "label": "process() Class объектісін құлыптайды, ал configure() оны кездейсоқ шақырған мысалды құлыптайды"
            },
            {
              "icon": "",
              "label": "Әдіс денесінде synchronized блогы қосымша қолданылмаса, екеуі де іс жүзінде ешнәрсені құлыптамайды"
            }
          ]
        },
        {
          "question": "Өріс volatile int counter = 0; деп жарияланған, әрі бірнеше ағын оған counter++ операциясын бір мезгілде орындайды. volatile мұнда жоғалған жаңартуларды болдырмай ма?",
          "options": [
            {
              "icon": "",
              "label": "Иә — volatile өріске жасалатын әрбір операцияны, соның ішінде инкрементті де, атомарлы етеді"
            },
            {
              "icon": "",
              "label": "Жоқ — volatile тек оқулардың ағындар арасында ең соңғы жазуды көретінін ғана кепілдендіреді (visibility); counter++ бірнеше қадамнан тұратын оқу-өзгерту-жазу операциясы, әрі volatile бұл қадамдарды атомарлы етпейді"
            },
            {
              "icon": "",
              "label": "Иә, бірақ тек int пен long өрістері үшін ғана, JVM 64-биттік мәндерді қалай өңдейтініне байланысты"
            },
            {
              "icon": "",
              "label": "Жоқ, әрі volatile int сияқты примитивті типтер үшін де көрінуді (visibility) кепілдендірмейді"
            }
          ]
        },
        {
          "question": "A интерфейсі мен B интерфейсі әрқайсысы describe() деген default әдісін жариялайды. Сынып екеуін де іске асырады, бірақ describe()-ты өзі override етпейді. Не болады?",
          "options": [
            {
              "icon": "",
              "label": "Компилятор A интерфейсінің нұсқасын автоматты түрде таңдайды, себебі ол implements тармағында бірінші тізілген"
            },
            {
              "icon": "",
              "label": "describe() шақырылған сайын екі нұсқа да кезекпен орындалады"
            },
            {
              "icon": "",
              "label": "Компиляция кезінде дұрыс, бірақ describe() алғаш шақырылғанда AmbiguousMethodException лақтырады"
            },
            {
              "icon": "",
              "label": "Компиляция қатесі — екі интерфейс бірдей default әдісін ұсынғанда, іске асырушы сынып екіұштылықты шешу үшін оны өзі override етуі керек, себебі Java қайсысын меңзегеніңізді болжамайды"
            }
          ]
        },
        {
          "question": "list.stream().filter(x -> x > 0).map(x -> x * 2); деп жазылады, бірақ нәтиже .collect() немесе .forEach() сияқты терминал операциясына ешқашан берілмейді. Бұл жол орындалғанда іс жүзінде не болады?",
          "options": [
            {
              "icon": "",
              "label": "Тізім элементтерімен мүлдем ештеңе болмайды — filter мен map тек конвейер сипаттамасын құратын жалқау (lazy) аралық операциялар; терминал операциясы болмаса, бұл конвейердің ешбір бөлігі нақты орындалмайды"
            },
            {
              "icon": "",
              "label": "Әр элемент дереу сүзгіленіп, түрлендіріледі, дәл терминал операциясы шақырылғандай"
            },
            {
              "icon": "",
              "label": "Тек filter дереу орындалады; map терминал операциясы пайда болғанша кейінге қалдырылады"
            },
            {
              "icon": "",
              "label": "Ол IllegalStateException лақтырады, себебі stream конвейерінің компиляциялануы үшін терминал операциясы қажет"
            }
          ]
        }
      ],
      "optionOrderVersion": "0154f9576054ad6f"
    }
  }
}
