JavaRush /Java блогу /Random-KY /Java'да автобокс жана кутудан чыгаруу
Viacheslav
Деңгээл

Java'да автобокс жана кутудан чыгаруу

Группада жарыяланган
<h2>Кириш сөз</h2>Программалоо тor, адамдар сүйлөгөн тил, жашап жана өзгөрүп турган сыяктуу, тилди колдонууга ыңгайлуураак кылуу үчүн анда жаңы кубулуштар пайда болот. Ал эми биз билгендей, тил биздин оюбузду ыңгайлуу түрдө билдирүүгө тийиш.
Java'да автобокс жана кутудан чыгаруу - 1
Ошентип, Java SE 5те бокс / кутудан чыгаруу механизми киргизилген. Жана Oracleдан өзүнчө окуу куралы ойду билдирүүнүн бул каражатынын өзгөчөлүктөрүнө арналган: Autoboxing жана Unboxing . <h2>Авто таңгактоо боксу</h2>Келгиле, автоматтык таңгактоочу бокстун мисалын карап көрөлү. Биринчиден, анын кантип иштээрин карап көрөлү. Келгиле, compilejava.net сайтын колдонуп , класс түзөлү:
public class App {
    public static void main(String[] args) {
        Integer portNumber = 8080;
        if (args.length != 0) {
            portNumber = Integer.valueOf(args[0]);
        }
        System.out.println("Port number is: " + portNumber);
    }
}
Жөнөкөй code. Биз киргизүү параметрин көрсөтүп, порттун маанисин өзгөртө алабыз. Биз көрүп тургандай, анткени биз порттун маанисин параметрлерден окуйбуз , аны аркылуу алуу аркылуу Stringалабыз . Ошондуктан, биз аны примитивдүү тип катары эмес, an object түрү катары көрсөтүүгө аргасызбыз . Жана бул жерде биз бир жагынан алабыз, бизде an object өзгөрмө бар, ал эми демейки маани примитив болуп саналат. Жана ал иштейт. Бирок биз сыйкырга ишенбейбиз, туурабы? Келгиле, алар айткандай, «капоттун астын» карап көрөлү. "ZIP жүктөө" баскычын чыкылdateу менен compilejava.net булак codeун жүктөп алыңыз. Андан кийин, жүктөлүп алынган архивди каталогго чыгарып, ага өтүңүз. Эми жасайлы: бул жерде App.class классыңыз үчүн түзүлгөн класс файлы. Биз төмөнкүдөй мазмунду көрөбүз: IntegerInteger.valueOfIntegerjavap -c -p App.class
Java'да автобокс жана кутудан чыгаруу - 2
Бул ошол эле белгилүү "bytecode". Бирок азыр биз үчүн эмнени көрүп жатканыбыз маанилүү. Биринчиден, 8080 примитив методдун аткаруу стекине жайгаштырылат, андан кийин Integer.valueOf аткарылат . Бул бокстун "сыйкыры". Жана сыйкырдын ичинде мындай көрүнөт:
Java'да автобокс жана кутудан чыгаруу - 3
Башкача айтканда, жаңысы кэштен алынат Integerже алынат Integer(кэш бул бүтүн сандардын массивинен башка эч нерсе эмес) сандын маанисине жараша. Албетте, Integerмынчалык бактылуу бирөө гана эмес. Байланыштуу примитивдик типтердин жана алардын орогучтарынын толук тизмеси бар (OOP дүйнөсүндөгү примитивдерди билдирген класстар). Бул тизме Oracle окуу куралынын эң ылдый жагында берилген: “ Autoboxing жана Unboxing ”. Дароо белгилей кетүү керек, примитивдерден жасалган массивдерде эч кандай үчүнчү тараптын китепканаларын туташтырбай туруп, "ороого" ээ эмес. Ошол. дан биз үчүн Arrays.asListжасаbyte . <h2>Кутудан чыгаруу</h2>Бокстун тескери процесси кутудан чыгаруу деп аталат. Пакеттен чыгуунун мисалын карап көрөлү: int[]ListInteger
public class App {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please, enter params");
            return;
        }
      	int value = Math.abs(Integer.valueOf(args[0]));
        System.out.println("Absolute value is: " + value);
    }

}
Math.absпримитивдерди гана кабыл алат. Эмне кылыш керек? Ороочу классында бул учур үчүн примитивди кайтарган атайын метод бар. Мисалы, бул intValueInteger ыкмасы . Байтcodeду карасак, ал мындай болот:
Java'да автобокс жана кутудан чыгаруу - 4
Көрүнүп тургандай, сыйкыр жок. Баары Java ичинде. Ал жөн гана "өзүнчө" иштейт. Биздин ыңгайлуулугубуз үчүн. <h2>Тырмоо</h2>
Java'да автобокс жана кутудан чыгаруу - 5
Ар кандай курал туура эмес колдонулса, өзүнө каршы күчтүү курал болуп калат. Жана Javaдагы автоматтык бокс / кутудан чыгаруу механизми да өзгөчө эмес. Биринчи, ачык салыштыруу аркылуу болот ==. Мен бул түшүнүктүү деп ойлойм, бирок келгиле, дагы бир жолу карап көрөлү:
public static void main(String[] args) {
    Integer inCacheValue = 127;
    Integer inCacheValue2 = 127;
    Integer notInCache = 128; // new Integer(129)
    Integer notInCache2 = 128; // new Integer(129)
    System.out.println(inCacheValue == inCacheValue2); //true
    System.out.println(notInCache == notInCache2); //false
}
Биринчи учурда, маани маанилердин кэшинен алынат Integer(жогоруда Бокстун түшүндүрмөсүн караңыз), ал эми экинчи учурда жаңы an object ар бир жолу түзүлөт. Бирок бул жерде ээлеп коюу керек. Бул жүрүм кэштин жогорку чегинен көз каранды ( java.lang.Integer.IntegerCache.high ). Мындан тышкары, бул чек башка орнотууларга байланыштуу өзгөрүшү мүмкүн. Бул темадагы талкууну stackoverflow боюнча окуй аласыз: Integer кэши канчалык чоң? Албетте, an objectилерди бирдей колдонуу менен салыштыруу керек: System.out.println(notInCache.equals(notInCache2)); Ошол эле механизм менен байланышкан экинчи маселе - бул өндүрүмдүүлүк. Javaдагы ар кандай бокс жаңы an objectти түзүүгө барабар. Эгер сан кэш маанилерине кирбесе (б.а. -128ден 127ге чейин), анда ар бир жолу жаңы an object түзүлөт. Эгер күтүлбөгөн жерден таңгактоо (б.а. бокс) циклде жүргүзүлсө, бул керексиз an objectтердин чоң өсүшүнө жана таштанды жыйноочунун иши үчүн ресурстардын сарпталышына алып келет. Ошондуктан, бул жөнүндө өтө бейкапар болбогула. Үчүнчүсү, азыраак ооруган тырмоо бир эле механизмден келип чыгат:
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
Бул codeдо адам катадан өтпөөгө аракет кылган. Бирок текшерүү жок null. Эгер киргизүүгө келсек null, анда түшүнүктүү катанын ордуна биз түшүнүксүз ката алабыз NullPointerException. Анткени салыштыруу үчүн, Java аткарууга value.intValueжана кыйроого аракет кылат, анткени... valueболот null. <h2> Корутунду </ h2> Бокс / кутудан чыгаруу механизми программистке азыраак code жазууга мүмкүндүк берет жана кээде примитивдерден an objectтерге жана артка айландыруу жөнүндө ойлонбойт. Бирок бул анын кантип иштээрин унутуш керек дегенди билдирбейт. Болбосо, сиз дароо пайда болбой турган ката кетиришиңиз мүмкүн. Биз толугу менен биздин көзөмөлүбүздө болбогон системанын бөлүктөрүнө (мисалы, бүтүн чек ара) таянбашыбыз керек. Бирок орогуч класстарынын бардык артыкчылыктары жөнүндө унутпаңыз (мисалы Integer). Көбүнчө бул орогуч класстарында жашооңузду жакшырта турган жана codeуңузду экспрессивдүү кыла турган кошумча статикалык ыкмалардын топтому бар. Бул жерде бир кууп мисал:
public static void main(String[] args) {
    int first = 1;
    int second = 5;
    System.out.println(Integer.max(first, second));
    System.out.println(Character.toLowerCase('S'));
}
Бардык нерседен туура тыянак: сыйкыр жок, кандайдыр бир ишке ашыруу бар. Жана баары биз күткөндөй боло бербейт. Мисалы, таңгак жок: System.out.println("The number is " + 8); Жогорудагы мисал компилятор тарабынан бир сапка оптималдаштырылат. Башкача айтканда, "Сан 8" деп жазгандай. Ал эми төмөндөгү мисалда эч кандай таңгак болбойт:
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
printlnОбъектти киргизүү катары кабыл алып, кандайдыр бир жол менен сызыктарды бириктиришибиз керек болгондо, бул кандай болушу мүмкүн . Саптар... ооба, ошондуктан мындай таңгак жок. Статикалык методдор бар Integer, бирок алардын айрымдары package. Башкача айтканда, биз аларды колдоно албайбыз, бирок Javaнын өзүндө аларды активдүү колдонсо болот. Бул жерде так ушундай. GetChars ыкмасы чакырылат, ал сандан символдордун массивин түзөт. Дагы бир сыйкыр жок, жөн гана Java). Ошентип, кандайдыр бир түшүнүксүз кырдаалда, сиз жөн гана ишке ашырууну карап, жок дегенде бир нерсе ордуна келет. #Вячеслав
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION