JavaRush /Java Blogu /Random-AZ /Java-da avtoboks və qutudan çıxarma
Viacheslav
Səviyyə

Java-da avtoboks və qutudan çıxarma

Qrupda dərc edilmişdir
<h2>Giriş</h2>İnsanların danışdığı, yaşadığı və dəyişdiyi dil kimi proqramlaşdırma dili, dilin istifadəsini daha rahat etmək üçün onda yeni hadisələr meydana çıxır. Və bildiyimiz kimi, dil fikirlərimizi rahat şəkildə ifadə etməlidir.
Java-da avtoboks və qutudan çıxarma - 1
Beləliklə, Java SE 5-də boxing/unboxing mexanizmi təqdim edildi. Oracle-dan ayrıca bir dərslik bu fikirləri ifadə edən vasitələrin xüsusiyyətlərinə həsr edilmişdir: Autoboxing və Unboxing . <h2>Avtomatik qablaşdırma Boks</h2>Gəlin avtomatik qablaşdırma Boks nümunəsinə baxaq. Əvvəlcə bunun necə işlədiyini görək. Gəlin compilejava.net saytından istifadə edək və sinif yaradaq:
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);
    }
}
Sadə kod. Giriş parametrini təyin edə və port dəyərini dəyişə bilərik. Gördüyümüz kimi, çünki parametrlərdən port dəyərini oxuyuruq , onu keçərək Stringəldə edirik . Buna görə də biz onu primitiv tip kimi deyil, obyekt tipi kimi göstərməyə məcbur oluruq . Və burada, bir tərəfdən, bir obyekt dəyişənimiz var və standart dəyər primitivdir. Və işləyir. Amma biz sehrə inanmırıq, elə deyilmi? Necə deyərlər, “başlıq altına” nəzər salaq. Mənbə kodunu compilejava.net saytından “ZIP-i yüklə” düyməsini klikləməklə yükləyin. Bundan sonra yüklənmiş arxivi qovluğa çıxarın və ona keçin. İndi edək: burada App.class sinifiniz üçün tərtib edilmiş sinif faylıdır. Bu kimi məzmun görəcəyik: IntegerInteger.valueOfIntegerjavap -c -p App.class
Java-da avtoboks və qutudan çıxarma - 2
Bu, eyni bədnam “bayt kodu”dur. Amma indi bizim üçün önəmli olan gördüklərimizdir. Əvvəlcə 8080 ibtidai metod icra yığınına yerləşdirilir və sonra Integer.valueOf yerinə yetirilir . Bu, boksun "sehridir". Və sehrin içərisində belə görünür:
Java-da avtoboks və qutudan çıxarma - 3
Yəni, mahiyyət etibarilə, nömrənin dəyərindən asılı olaraq keşdən yenisi alınacaq Integervə ya alınacaq (kesh sadəcə Tam ədədlər massivindən başqa bir şey deyil). IntegerTəbii ki, Integertəkcə bir nəfər belə şanslı olmayıb. Əlaqədar ibtidai növlərin və onların sarğılarının (OOP dünyasında primitivləri təmsil edən siniflər) tam siyahısı var. Bu siyahı Oracle-dan Təlimatın ən aşağı hissəsində verilmişdir: “ Autoboxing and Unboxing ”. Dərhal qeyd etmək lazımdır ki, primitivlərdən hazırlanmış massivlərin heç bir üçüncü tərəf kitabxanalarını birləşdirmədən "sarğı" yoxdur. Bunlar. ' dan bizim üçün Arrays.asListetməyəcək . <h2>Qutudan çıxarma</h2>Boksa əks proses qutudan çıxarma adlanır. Qablaşdırmadan bir nümunəyə baxaq: 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.absyalnız primitivləri qəbul edir. Nə etməli? Sarmalayıcı sinfinin bu hal üçün primitiv qaytaran xüsusi metodu var. Məsələn, bu intValueInteger metodudur . Bayt koduna baxsaq, bu belədir:
Java-da avtoboks və qutudan çıxarma - 4
Görünür, heç bir sehr yoxdur. Hər şey Java daxilindədir. O, sadəcə olaraq "öz-özünə" işləyir. Rahatlığımız üçün. <h2>Dırmıq</h2>
Java-da avtoboks və qutudan çıxarma - 5
İstənilən alət, düzgün istifadə edilmədikdə, özünə qarşı nəhəng bir silaha çevrilir. Java-da avtomatik boks / qutudan çıxarma mexanizmi də istisna deyil. Birinci, aşkar müqayisə ==. Düşünürəm ki, bu aydındır, amma gəlin yenidən baxaq:
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
}
Birinci halda, dəyər dəyər ön yaddaşından götürülür Integer(yuxarıda Boxing izahına baxın), ikinci halda isə hər dəfə yeni obyekt yaradılacaq. Ancaq burada rezervasiya etməyə dəyər. Bu davranış önbelleğin yüksək sərhədindən asılıdır ( java.lang.Integer.IntegerCache.high ). Bundan əlavə, bu limit digər parametrlərə görə dəyişə bilər. Bu mövzuda müzakirəni stackoverflow-da oxuya bilərsiniz: Tam ədəd önbelleği nə qədər böyükdür? Təbii ki, obyektləri bərabərlərdən istifadə etməklə müqayisə etmək lazımdır: System.out.println(notInCache.equals(notInCache2)); Eyni mexanizmlə əlaqəli ikinci problem performansdır. Java-da istənilən boks yeni obyekt yaratmağa bərabərdir. Əgər nömrə keş dəyərlərinə daxil deyilsə (yəni -128-dən 127-yə qədər), onda hər dəfə yeni obyekt yaradılacaq. Birdən qablaşdırma (yəni boks) bir döngədə aparılırsa, bu, lazımsız obyektlərin böyük artmasına və zibil toplayıcının işi üçün resursların istehlakına səbəb olacaqdır. Buna görə də, bu barədə çox ehtiyatsız davranmayın. Üçüncüsü, daha az ağrılı deyil, eyni mexanizmdən qaynaqlanır:
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
Bu kodda şəxs aydın şəkildə səhvdən keçməməyə çalışırdı. Amma heç bir çek yoxdur null. Söhbət girişdən gedirsə null, o zaman başa düşülən xətanın əvəzinə anlaşılmaz bir səhv alacağıq NullPointerException. Çünki müqayisə üçün Java yerinə yetirməyə və qəzaya uğramağa çalışacaq value.intValue, çünki... valueolacaq null. <h2>Nəticə</h2>Boks / qutudan çıxarma mexanizmi proqramçıya daha az kod yazmağa imkan verir və bəzən primitivlərdən obyektlərə və geriyə çevrilməyi düşünmür. Ancaq bu, onun necə işlədiyini unutmalı olduğunuz demək deyil. Əks halda, dərhal görünməyəcək bir səhv edə bilərsiniz. Sistemin tam nəzarətimiz altında olmayan hissələrinə (məsələn, tam ədəd sərhədi kimi) etibar etməməliyik. Ancaq sarğı siniflərinin bütün üstünlükləri haqqında unutmayın (kimi Integer). Çox vaxt bu sarğı sinifləri həyatınızı yaxşılaşdıracaq və kodunuzu daha ifadəli edəcək bir sıra əlavə statik üsullara malikdir. Budur bir tutma nümunəsi:
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'));
}
Hər şeydən düzgün nəticə budur ki, sehr yoxdur, bir növ reallaşma var. Və hər şey həmişə gözlədiyimiz kimi olmayacaq. Məsələn, qablaşdırma yoxdur: System.out.println("The number is " + 8); Yuxarıdakı nümunə kompilyator tərəfindən bir sətirdə optimallaşdırılacaq. Yəni, sanki “Rəqəm 8-dir” yazmısınız. Aşağıdakı nümunədə də heç bir qablaşdırma olmayacaq:
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
Necə ola bilər ki, biz printlnbir obyekti giriş kimi qəbul edirik və hansısa şəkildə xətləri birləşdirməliyik. Xətlər... bəli, buna görə də belə qablaşdırma yoxdur. Statik üsullar var Integer, lakin onlardan bəziləri package. Yəni biz onlardan istifadə edə bilmərik, amma Java-nın özündə aktiv şəkildə istifadə oluna bilər. Burada da məhz belədir. GetChars metodu çağırılacaq ki, bu da nömrədən simvollar massivi yaradır. Yenə sehr yoxdur, sadəcə Java). Beləliklə, hər hansı bir qeyri-müəyyən vəziyyətdə, sadəcə icraya baxmaq lazımdır və ən azı bir şey yerinə düşəcəkdir. #Viaçeslav
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION