Java Koleksiyonları neden İlkel türlerini doğrudan depolamıyor?


123

Java koleksiyonları, ilkel türleri değil yalnızca Nesneleri depolar; ancak sarmalayıcı sınıflarını saklayabiliriz.

Neden bu kısıtlama?


2
Bu kısıtlama, ilkellerle uğraştığınızda ve göndermek için Kuyrukları kullanmak istediğinizde ve gönderme oranlarınız çok hızlı olduğunda kötüdür. Şu anda çok fazla zaman alan otomatik kutulama sorunuyla uğraşıyorum.
JPM

Teknik olarak, ilkel türler nesnelerdir (tam olarak tekil örnekler), classJVM yerine a ile tanımlanmazlar . Bildirimi int i = 1tanımlar nesnesinin tekil örneği için bir işaretçi tanımlayan intJVM, değer olarak ayarlanmış 1JVM tanımlanan bir yerde. Evet, Java'daki işaretçiler - bu sadece dil uygulamasıyla sizden soyutlanmıştır. İlkel öğeler Genel olarak kullanılamaz çünkü dil, tüm genel türlerin süper türden olması gerektiğini öngörür Object- bu nedenle çalışma zamanında A<?>derleme neden olur A<Object>.
Robert E Fry

1
@RobertEFry ilkel türler Java'da nesneler değildir , bu nedenle tekil örnekler ve benzeri hakkında yazdığınız her şey temelde yanlış ve kafa karıştırıcıdır. Java Dil Spesifikasyonunun bir nesnenin ne olduğunu tanımlayan "Türler, Değerler ve Değişkenler" bölümünü okumanızı öneririm : "Bir nesne (§4.3.1), bir sınıf türünün dinamik olarak oluşturulmuş bir örneğidir veya dinamik olarak oluşturulmuş bir dizidir. "
typeracer

Yanıtlar:


99

Bu bir Java tasarım kararıydı ve bazılarının bir hata olarak gördüğü bir karar. Kapsayıcılar Nesneleri ister ve ilkeller, Nesneden türetilmez.

Bu, .NET tasarımcılarının JVM'den öğrendiği ve birçok durumda kutulamanın ortadan kaldırılması için değer türleri ve jenerikleri uyguladığı bir yerdir. CLR'de, genel kapsayıcılar, temel kapsayıcı yapısının bir parçası olarak değer türlerini depolayabilir.

Java, JVM desteği olmadan derleyiciye% 100 genel destek eklemeyi seçti. JVM olduğu gibi, "nesne olmayan" bir nesneyi desteklemez. Java jenerikleri, paketleyici yokmuş gibi davranmanıza izin verir, ancak yine de boks performans fiyatını ödersiniz. Bu, belirli program sınıfları için ÖNEMLİDİR.

Boks teknik bir uzlaşmadır ve bunun dile sızan uygulama detayı olduğunu düşünüyorum. Otomatik kutulama güzel sözdizimsel şekerdir, ancak yine de bir performans cezasıdır. Bir şey olursa, derleyicinin otomatik kutuya girdiğinde beni uyarmasını isterim. (Tüm bildiğim, şimdi olabilir, bu cevabı 2010'da yazdım).

SO hakkında boks hakkında iyi bir açıklama: Neden bazı diller Boks ve Kutudan Çıkarma gerektirir?

Ve Java jeneriklerinin eleştirisi: Neden bazıları Java'nın jenerik uygulamasının kötü olduğunu iddia ediyor?

Java'nın savunmasında geriye dönüp eleştirmek kolaydır. JVM, zaman testine dayanmıştır ve birçok açıdan iyi bir tasarımdır.


6
Bir hata değil, dikkatlice seçilmiş bir değiş tokuşun Java'ya gerçekten çok iyi hizmet ettiğine inanıyorum.
DJClayworth

13
NET'in ondan öğrenmesi ve otomatik kutulamayı baştan, genelleri sanal makinede kutulama ek yükü olmadan uygulaması yeterli bir hataydı. Java'nın kendi düzeltme girişimi, yalnızca otomatik kutunun performansına karşı hiçbir kutulama olmamasından muzdarip olan sözdizimi düzeyinde bir çözümdü. Java'nın uygulaması, büyük veri yapılarında zayıf performans gösterdi.
codenheim

2
@mrjoltcola: IMHO, varsayılan otomatik kutulama bir hatadır, ancak değişkenleri ve parametreleri kendilerine verilen değerleri otomatik olarak kutuya alması gereken etiketlemenin bir yolu olmalıydı. Şimdi bile, belirli değişkenlerin veya parametrelerin yeni otomatik kutulu değerleri kabul etmemesi gerektiğini belirtmek için bir yol eklenmesi gerektiğini düşünüyorum [örneğin , kutulu tamsayıları tanımlayan Object.ReferenceEqualstürden referansları geçirmek yasal olmalı Object, ancak yasal olmamalıdır. bir tamsayı değeri iletin]. Java'nın otomatik kutudan çıkarılması IMHO'dur.
supercat

18

Uygulamayı kolaylaştırır. Java ilkelleri Nesne olarak kabul edilmediğinden, bu ilkellerin her biri için ayrı bir koleksiyon sınıfı oluşturmanız gerekir (paylaşılacak şablon kodu yok).

Elbette bunu yapabilirsiniz, sadece GNU Trove , Apache Commons Primitives veya HPPC'ye bakın .

Gerçekten büyük koleksiyonlara sahip olmadığınız sürece, paketleyicilerin ek yükü insanların ilgilenmesi için yeterli değildir (ve gerçekten büyük ilkel koleksiyonlarınız olduğunda, onlar için özel bir veri yapısı kullanmak / oluşturmak için çaba harcamak isteyebilirsiniz. ).


11

Bu, iki gerçeğin birleşimidir:

  • Java ilkel türleri başvuru türleri değildir (örneğin int, bir değildir Object)
  • Java, referans türlerini silmeyi kullanarak jenerikler yapar (örneğin, a List<?>gerçekten List<Object>çalışma zamanında)

Bunların her ikisi de doğru olduğundan, genel Java koleksiyonları ilkel türleri doğrudan depolayamaz. Kolaylık sağlamak amacıyla, ilkel türlerin otomatik olarak referans türler olarak kutulanmasına izin vermek için otomatik kutulama tanıtılmıştır. Bununla ilgili hiç kuşkunuz olmasın, koleksiyonlar yine de nesne referanslarını saklıyor.

Bu önlenebilir miydi? Belki.

  • Eğer bir bir intise Object, kutu tiplerine hiç gerek yoktur.
  • Tür silmeyi kullanarak jenerikler yapılmadıysa, ilkeller tür parametreleri için kullanılabilirdi.

8

Otomatik kutulama ve otomatik kutudan çıkarma kavramı vardır . Bir Java derleyicisinde intbir tane saklamaya çalışırsanız, List<Integer>onu otomatik olarak bir Integer.


1
Autoboxing, Generics ile birlikte Java 1.5'te tanıtıldı.
Jeremy

1
Ama bu bir derleme zamanı olayı; performans avantajı olmayan sözdizimi şekeri. Java derleyici otomatik kutuları, dolayısıyla .NET gibi jenerikler kutuyu içermeyen VM uygulamalarıyla karşılaştırıldığında performans düşüşü.
codenheim

1
@mrjoltcola: Ne demek istiyorsun? Sadece gerçekleri paylaşıyordum, tartışmıyordum.
Jeremy

3
Demek istediğim, sözdizimi ve performans arasındaki farkı belirtmek önemlidir. Ayrıca yorumlarımı tartışmayı değil gerçek paylaşımını da dikkate alıyorum. Teşekkürler.
codenheim

2

Gerçekten bir kısıtlama değil, değil mi?

İlkel değerleri depolayan bir koleksiyon oluşturmak isteyip istemediğinizi düşünün. İnt, float veya char saklayabilen bir koleksiyonu nasıl yazarsınız? Büyük olasılıkla birden fazla koleksiyonla sonuçlanacaksınız, bu nedenle bir intlist ve bir charlist vb.'ye ihtiyacınız olacak.

Bir koleksiyon sınıfı yazarken Java'nın nesne yönelimli doğasından yararlanarak, herhangi bir nesneyi depolayabilir, böylece yalnızca bir koleksiyon sınıfına ihtiyacınız olur. Bu çok biçimlilik fikri çok güçlüdür ve kitaplıkların tasarımını büyük ölçüde basitleştirir.


7
"İnt, float veya char saklayabilen bir koleksiyonu nasıl yazarsınız?" - Her şeyin bir nesne olduğunu iddia etmenin cezasını ödemeyen diğer diller gibi uygun şekilde uygulanan jenerikler / şablonlar ile.
codenheim

Java'nın altı yıldır neredeyse hiç bir ilkel koleksiyonunu depolamak istemedim. Referans nesneleri kullanmanın fazladan zaman ve alan maliyetini istemiş olabileceğim birkaç durumda bile ihmal edilebilirdi. Özellikle birçok insanın Map <int, T> istediğini düşündüğünü ve bir dizinin bu numarayı çok güzel yapacağını unuttuğunu görüyorum.
DJClayworth

2
@DJClayworth Bu, yalnızca anahtar değerleri seyrek değilse iyi çalışır. Elbette, anahtarları takip etmek için bir yardımcı dizi kullanabilirsiniz, ancak bunun kendine ait sorunları vardır: nispeten verimli erişim, ikili aramaya izin vermek için her iki diziyi de anahtar sırasına göre sıralı tutmayı gerektirir, bu da ekleme ve silme işlemine neden olur. ekleme / silme, eklenen öğelerin daha önce silinmiş bir öğenin olduğu yerde sona ermesi ve / veya dizilere bazı tamponların serpiştirilmesi gibi bir model oluşturmadıkça verimsizdir. Kullanılabilir kaynaklar vardır, ancak içeride olması güzel olurdu Java'nın kendisi.
JAB

@JAB Aslında anahtarlar seyrekse iyi çalışıyor, sadece seyrek olmadıklarından daha fazla belleğe ihtiyacı var. Ve eğer anahtarlar seyrekse, bu sayıların çok olmadığı ve anahtar olarak Tamsayı kullanmanın iyi çalıştığı anlamına gelir. En az belleğe ihtiyaç duyan yaklaşımı kullanın. Ya da umursamıyorsanız hangisini hissederseniz.
DJClayworth

0

Sanırım bu alanda JDK'da ilerleme görebiliriz, muhtemelen Java 10'da bu JEP - http://openjdk.java.net/jeps/218 .

Bugün koleksiyonlarda ilkelleri kutlamaktan kaçınmak istiyorsanız, birkaç üçüncü taraf alternatifi vardır. Daha önce bahsedilen üçüncü taraf seçeneklerine ek olarak Eclipse Collections , FastUtil ve Koloboke da vardır .

İlkel haritaların bir karşılaştırması da bir süre önce şu başlıkla yayınlandı: Büyük HashMap'e genel bakış: JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove . GS Koleksiyonları (Goldman Sachs) kitaplığı Eclipse Foundation'a taşındı ve artık Eclipse Koleksiyonları olarak değiştirildi.


0

Ana sebep, java tasarım stratejisidir. ++ 1) koleksiyonlar, manipülasyon için nesneler gerektirir ve ilkel öğeler nesneden türetilmez, bu nedenle başka bir neden olabilir. 2) Java ilkel veri türleri, örneğin başvuru türü değildir. int bir nesne değildir.

Üstesinden gelmek:-

otomatik kutulama ve otomatik kutudan çıkarma konseptimiz var. bu nedenle, ilkel veri türlerini depolamaya çalışıyorsanız, derleyici bunu otomatik olarak ilkel veri sınıfının nesnesine dönüştürür.

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.