Boks ve boks nedir ve takaslar nelerdir?


135

Açık, özlü ve doğru bir cevap arıyorum.

İdeal olarak gerçek cevap olarak, iyi açıklamalara bağlantılar hoş geldiniz.


2
Bu gerçekten dile özgü değil mi?
Henk Holterman

3
@HenkHolterman kesinlikle dile özgü değildir, ancak tüm dillerle de ilgili değildir - bu ayrım, örneğin dinamik olarak yazılan çoğu dil için önemsiz olacaktır. Bunun yerine hangi etiketin kullanılabileceğinden emin değilim - language-but-not-type-agnostic? static-language-agnostic? SO'nun ayrıma ihtiyacı olduğundan emin değilim; meta için iyi bir soru olabilir.
Keith

Yanıtlar:


189

Kutulu değerler, ilkel tipler * etrafında minimum paketleyici olan veri yapılarıdır *. Kutulu değerler genellikle öbek üzerindeki nesnelere işaretçiler olarak depolanır .

Böylece, kutulu değerler daha fazla bellek kullanır ve erişmek için en az iki bellek araması alır: bir kez işaretçiyi almak için bir diğeri ve bu işaretçiyi ilkeye kadar takip etmek. Açıkçası bu, iç döngülerinizde istediğiniz bir şey değildir. Öte yandan, kutulu değerler sistemdeki diğer tiplerle tipik olarak daha iyi oynar. Dilde birinci sınıf veri yapıları oldukları için, diğer veri yapılarının sahip olduğu beklenen meta verilere ve yapıya sahiptirler.

Java ve Haskell'de genel koleksiyonlar kutusuz değerler içeremez. .NET'teki genel koleksiyonlar, cezalandırılmamış kutulanmamış değerleri tutabilir. Java'nın jenerikleri yalnızca derleme zamanı tür denetimi için kullanıldığında, .NET çalışma zamanında başlatılan her genel tür için belirli sınıflar oluşturur .

Java ve Haskell'in kutulanmamış dizileri vardır, ancak diğer koleksiyonlardan belirgin şekilde daha az uygundurlar. Bununla birlikte, en yüksek performans gerektiğinde, boks ve kutudan çıkarma yükünü önlemek için biraz rahatsızlık vermeye değer.

* Bu tartışma için, ilkel bir değer, yığındaki bir değere işaretçi olarak depolanmak yerine çağrı yığınında saklanabilecek değerdir. Genellikle bu sadece makine tipleri (ints, float, vb.), Yapılar ve bazen statik boyutlu dizilerdir. .NET-land onlara değer türleri (referans türlerinin aksine) der. Java insanları onlara ilkel türler diyor. Haskellions onları kutusuz olarak adlandırır.

** Ayrıca bu cevapta Java, Haskell ve C # üzerine odaklanıyorum, çünkü bunu biliyorum. Değeri için, Python, Ruby ve Javascript'in hepsi sadece kutulu değerlere sahiptir. Bu aynı zamanda "Her şey bir nesnedir" yaklaşımı olarak da bilinir ***.

*** Uyarı: Yeterince gelişmiş bir derleyici / JIT, bazı durumlarda, kaynağa bakarken anlamsal olarak kutulanmış bir değerin çalışma zamanında güvenli bir şekilde kutulanmamış bir değer olabileceğini algılayabilir. Özünde, parlak dil uygulayıcıları sayesinde kutularınız bazen ücretsizdir.


Neden kutulu bir değer olsa da, CLR ya da form boksu değerlerinden ne faydalanır?
PositiveGuy

Kısacası (ha ha), onlar sadece başka bir Nesne, ki bu çok uygun. Temel öğeler (en azından Java'da) Nesneden alçalmaz, alanlara sahip olamaz, yöntemlere sahip olamaz ve genellikle diğer değer türlerinden çok farklı davranır. Öte yandan, onlarla çalışmak çok hızlı ve yerden tasarruf sağlayabilir. Böylece ticaret kapalı.
Peter Burns

2
Javascript, kutusuz gelenler ve şamandıralardan oluşan diziler (yeni UInt32Array vb.) Olarak adlandırılır.
nponeccop

126

dan Özet olarak C # 3.0 :

Boks, bir değer türünü referans türüne dönüştürme eylemidir:

int x = 9; 
object o = x; // boxing the int

kutudan çıkarma ... tersi:

// unboxing o
object o = 9; 
int x = (int)o; 

72

Boks ve kutudan çıkarma, ilkel bir değeri bir nesne yönelimli sarıcı sınıfına (boks) dönüştürme veya bir değeri nesne yönelimli bir sargı sınıfından ilkel değere (kutudan çıkarma) dönüştürme işlemidir.

Örneğin, java'da, bir intdeğeri bir Integerkutuda (boks) dönüştürmeniz gerekebilir, Collectionçünkü temel öğeler Collectionyalnızca bir nesnede saklanamayacaktır . Ama onu geri Collectionalmak istediğinizde değeri bir olarak almak isteyebilirsiniz, böylece intbir Integerkutuyu açabilirsiniz .

Boks ve kutudan çıkarma doğal olarak kötü değildir , ancak bir ödünleşmedir. Dil uygulamasına bağlı olarak, sadece ilkelleri kullanmaktan daha yavaş ve daha fazla bellek yoğun olabilir. Ancak, daha yüksek düzeyde veri yapıları kullanmanızı ve kodunuzda daha fazla esneklik elde etmenizi sağlayabilir.

Günümüzde en çok Java'nın (ve diğer dillerin) "otomatik kutulama / otomatik kutulama" özelliği bağlamında tartışılmaktadır. İşte otomatik boksun java merkezli bir açıklaması .


23

Net olarak:

Genellikle bir işlevin ne tür bir değişken kullanacağına güvenemezsiniz, bu nedenle en düşük ortak paydadan - in .net bu kadar uzanan bir nesne değişkeni kullanmanız gerekir object.

Ancak objectbir sınıftır ve içeriğini referans olarak saklar.

List<int> notBoxed = new List<int> { 1, 2, 3 };
int i = notBoxed[1]; // this is the actual value

List<object> boxed = new List<object> { 1, 2, 3 };
int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int

Her ikisi de aynı bilgileri tutarken, ikinci liste daha büyük ve daha yavaştır. İkinci listede her bir değer aslında bir başvurusudur objecttutar int.

Bunun nedeni kutulu denir inttarafından sarılır object. Geri alındığında intkutusuzdur - değerine geri dönüştürülür.

Değer türleri (yani tümü structs) için bu yavaştır ve potansiyel olarak çok daha fazla alan kullanır.

Referans türleri (yani tümü classes) için, yine de referans olarak saklandıklarından, bu çok daha az problemdir.

Kutulu bir değer türüyle ilgili başka bir sorun da, değerden ziyade kutuyla uğraştığınız açık değildir. Eğer ikisini karşılaştırdığımızda structso zaman değerlerini karşılaştırarak yapıyor ancak ikisini karşılaştırdığımızda classes(varsayılan olarak) o zaman referansı kıyaslıyorsun - yani bu aynı örneği vardır?

Kutulu değer türleriyle uğraşırken bu kafa karıştırıcı olabilir:

int a = 7;
int b = 7;

if(a == b) // Evaluates to true, because a and b have the same value

object c = (object) 7;
object d = (object) 7;

if(c == d) // Evaluates to false, because c and d are different instances

Etrafında çalışmak kolaydır:

if(c.Equals(d)) // Evaluates to true because it calls the underlying int's equals

if(((int) c) == ((int) d)) // Evaluates to true once the values are cast

Ancak kutulu değerlerle uğraşırken dikkatli olmak başka bir şeydir.


1
Vb.net'te eşitlik anlambilimi arasındaki fark daha açıktır, Objecteşitlik operatörünü uygulamamaktadır, ancak sınıf tipleri Isoperatörle karşılaştırılabilir ; tersine, Int32eşitlik operatörü ile kullanılabilir, ancak kullanılamaz Is. Bu ayrım, ne tür bir karşılaştırmanın yapıldığını daha açık hale getirir.
supercat

4

Boxingbir değer türünün referans türüne dönüştürülmesi işlemidir. Halbuki Unboxingbir referans türünün bir değer türüne dönüştürülmesidir.

EX: int i = 123;
    object o = i;// Boxing
    int j = (int)o;// UnBoxing

: Değer Türleri vardır int, charve structures, enumerations. Referans Tipleri şunlardır: Classes, interfaces, arrays, stringsveobjects


3

.NET FCL genel koleksiyonları:

List<T>
Dictionary<TKey, UValue>
SortedDictionary<TKey, UValue>
Stack<T>
Queue<T>
LinkedList<T>

hepsi önceki koleksiyon uygulamalarında boks ve kutudan çıkarma performans sorunlarının üstesinden gelmek için tasarlanmıştır.

Daha fazla bilgi için, bkz. Bölüm 16, CLR üzerinden C # (2. Baskı) .


1

Boks ve kutudan çıkarma, değer türlerinin nesne olarak ele alınmasını kolaylaştırır. Boks, bir değeri nesne başvuru türünün bir örneğine dönüştürmek anlamına gelir. Örneğin Int, bir sınıf ve intbir veri türüdür. dönüştürmeint için Intboks bir örnek dönüştürülmesi ise, bir Intile intkutudan çıkarma olup. Konsept, çöp toplamada, Kutudan Çıkarmada yardımcı olarak, nesne türünü değer türüne dönüştürür.

int i=123;
object o=(object)i; //Boxing

o=123;
i=(int)o; //Unboxing.

Javascript'te var ii = 123; typeof ii döndürür number. var iiObj = new Number(123); typeof iiObjdöner object. typeof ii + iiObjdöner number. Yani bu boksun javascript eşdeğeri. Aritmetiği gerçekleştirmek ve kutusuz bir değeri döndürmek için iiObj değeri otomatik olarak ilkel bir sayıya (kutulanmamış) dönüştürülür.
Pats

-2

Diğer her şey gibi, otomatik boks da dikkatli kullanılmazsa sorunlu olabilir. Klasik bir NullPointerException ile sonuçlanmak ve onu takip edememek. Bir hata ayıklayıcı ile bile. Bunu dene:

public class TestAutoboxNPE
{
    public static void main(String[] args)
    {
        Integer i = null;

        // .. do some other stuff and forget to initialise i

        i = addOne(i);           // Whoa! NPE!
    }

    public static int addOne(int i)
    {
        return i + 1;
    }
}

Bu sadece kötü bir koddur ve otomatik boks ile ilgisi yoktur. Değişken ierken başlatılır. Integer i;Derleyicinin başlatmayı unuttuğunuzu gösterebilmesi için boş bir bildirim ( ) yapın ya da değerini öğreninceye kadar bildirmek için bekleyin.
erickson

Hmm, eğer bir try catch bloğu içinde bir şey yaparsam derleyici beni bir şeyle başlatmaya zorlar. Bu gerçek bir kod değil - nasıl olabileceğinin bir örneği.
PEELY

Bu ne gösteriyor? Tamsayı nesnesini kullanmak için kesinlikle hiçbir neden yoktur. Bunun yerine şimdi potansiyel bir NullPointer ile uğraşmak zorundasınız.
Richard Clayton
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.