JavaRush /Java Blog /Random-TL /Autoboxing at unboxing sa Java

Autoboxing at unboxing sa Java

Nai-publish sa grupo
<h2>Introduction</h2>Isang programming language, tulad ng wikang sinasalita ng mga tao, buhay at pagbabago, ang mga bagong phenomena ay lumalabas dito upang gawing mas maginhawang gamitin ang wika. At tulad ng alam natin, ang wika ay dapat maginhawang ipahayag ang ating mga saloobin.
Автоупаковка и распаковка в Java - 1
Kaya, sa Java SE 5, ipinakilala ang mekanismo ng boxing/unboxing. At ang isang hiwalay na tutorial mula sa Oracle ay nakatuon sa mga tampok ng paraan ng pagpapahayag ng mga saloobin: Autoboxing at Unboxing . <h2>Auto-packing Boxing</h2>Tingnan natin ang isang halimbawa ng auto-packing Boxing. Una, tingnan natin kung paano ito gumagana. Gamitin natin ang site compilejava.net at lumikha ng isang klase:
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);
    }
}
Simpleng code. Maaari naming tukuyin ang input parameter at baguhin ang halaga ng port. Tulad ng nakikita natin, dahil binabasa namin ang halaga ng port mula Stringsa mga parameter, nakukuha namin Integerito sa pamamagitan ng pagkuha nito Integer.valueOf. Samakatuwid, napipilitan kaming tukuyin ito hindi bilang isang primitive na uri, ngunit bilang isang uri ng bagay Integer. At narito tayo sa isang banda, mayroon tayong object variable, at ang default na halaga ay primitive. At ito ay gumagana. Pero hindi naman tayo naniniwala sa magic diba? Tingnan natin ang "sa ilalim ng talukbong," gaya ng sinasabi nila. I-download ang source code mula sa compilejava.net sa pamamagitan ng pag-click sa “Download ZIP”. Pagkatapos nito, i-extract ang na-download na archive sa isang direktoryo at pumunta dito. Ngayon gawin natin: javap -c -p App.classkung saan ang App.class ay ang pinagsama-samang file ng klase para sa iyong klase. Makakakita tayo ng ganitong nilalaman:
Автоупаковка и распаковка в Java - 2
Ito ang parehong kilalang "bytecode". Ngunit ang mahalaga sa atin ngayon ay ang nakikita natin. Una, ang 8080 primitive ay inilalagay sa method execution stack, at pagkatapos ay ang Integer.valueOf ay ipapatupad . Ito ang "magic" ng boxing. At sa loob ng magic ay ganito ang hitsura:
Автоупаковка и распаковка в Java - 3
Ibig sabihin, sa esensya, isang bago ang kukunin Integero makukuha Integermula sa cache (ang cache ay hindi hihigit sa isang array ng Integers) depende sa halaga ng numero. Natural, Integerhindi lang isa ang napakaswerte. Mayroong isang buong listahan ng mga nauugnay na primitive na uri at ang kanilang mga wrapper (mga klase na kumakatawan sa mga primitive sa mundo ng OOP). Ang listahang ito ay ibinigay sa pinakailalim ng Tutorial mula sa Oracle: “ Autoboxing at Unboxing ”. Mahalagang tandaan kaagad na ang mga array na ginawa mula sa mga primitive ay walang "wrapper" nang hindi nagkokonekta sa anumang mga third-party na library. Yung. Arrays.asListay hindi gagawa ng para int[]sa amin Listmula sa Integer's. <h2>Pag-unboxing</h2>Ang pabalik na proseso sa boxing ay tinatawag na unboxing unboxing. Tingnan natin ang isang halimbawa ng pag-unpack:
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.abstumatanggap lamang ng mga primitive. Anong gagawin? Ang klase ng wrapper ay may espesyal na pamamaraan para sa kasong ito na nagbabalik ng primitive. Halimbawa, ito ang intValueInteger method . Kung titingnan natin ang bytecode, ito ay ganito:
Автоупаковка и распаковка в Java - 4
Kumbaga, walang magic. Ang lahat ay nasa loob ng Java. Gumagana lamang ito "mag-isa". Para sa aming kaginhawaan. <h2>Kalaykay</h2>
Автоупаковка и распаковка в Java - 5
Любой инструмент при неправильном использовании становится грозным оружием против самого себя. И механизм автоупаковка и распаковка boxing/unboxing в 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
}
В первом случае, meaning берётся из кэша Integer значений (см. объяснение Boxing выше), а во втором случае будет создаваться каждый раз новый an object. Но тут стоит оговориться. Это поведение зависит от верхней границы кэша (java.lang.Integer.IntegerCache.high). Кроме того, эта граница может измениться и из-за других настроек. На эту тему можно ознакомиться с обсуждением на stackoverflow: How large is the Integer cache? Естественно, an objectы нужно сравнивать через equals: System.out.println(notInCache.equals(notInCache2)); Вторая проблема, связанная с этим же механизмом – производительность. Любая упаковка в Java равносильна созданию нового an object. Если число не входит в значения из кэша (т.е. в -128 до 127), то будет каждый раз создаваться новый an object. Если вдруг упаковка (т.е. boxing) будет производиться в цикле, это вызовет огромный прирост ненужных an objectов и потребление ресурсов на работу сборщика мусора. Поэтому, не стоит слишком безрассудно относится к этому. Третьи не менее больные грабли вытекают из того же механизма:
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
В этом codeе человек явно пытался не пройти мимо ошибки. Но тут нет проверки на null. Если на вход придёт null, то instead of понятной ошибки мы получим невнятный NullPointerException. Потому что для сравнения Java попробует выполнить value.intValue и свалится, т.к. value будет null. <h2>Вывод</h2>Механизм boxing/unboxing позволяет программисту писать меньше codeа и даже порой не думать о преобразовании из примитивов в an objectы и обратно. Но это не значит, что нужно забывать, How это работает. Иначе можно допустить ошибку, которая может всплыть не сразу. Не стоит полагаться на части системы, которые не fully под нашим контролем (How например граница integer). Но и не стоит забывать про все преимущества классов-обёрток (вроде 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'));
}
Так же правильный вывод из всего - нет магии, есть Howая-то реализация. И не везде будет всегда то, что мы ожидаем. Например тут нет упаковки: System.out.println("The number is " + 8); Пример выше компилятором будет соптимизирован в одну строку. То есть словно вы написали «The number is 8». И в примере ниже тоже не будет упаковки:
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
Как же так, когда у нас println принимает на вход an object и нужно How-то соединить строки. Строки… да, именно поэтому нет упаковки, How таковой. У Integer есть статические методы, но некоторые из них уровня package. То есть мы их не можем использовать, а вот в самой Java они могут активно использоваться. Вот тут How раз такой случай. Будет вызван метод getChars, который из числа делает массив символов. Опять же, ниHowой магии, только Java ). Так что в любой непонятной ситуации стоит просто посмотреть реализацию и хоть что-то да встанет на свои места. #Viacheslav
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION