it-swarm.dev

Java'nın jenerikleriyle ilgili sorun nedir?

Java'nın jenerik ilaç uygulamasını bozan bu site yayınlarında birkaç kez gördüm. Şimdi, dürüstçe söyleyebilirim ki onları kullanırken herhangi bir sorun yaşamadım. Ancak, kendimi genel bir sınıf yapmaya çalışmadım. Peki, Java'nın genel desteğiyle ilgili sorunlarınız neler?

50
Michael K

Java'nın genel uygulaması tip silme kullanır. Bu, güçlü yazılan genel koleksiyonlarınızın aslında çalışma zamanında Object türünde olduğu anlamına gelir. Genel bir koleksiyona eklendiğinde ilkel türlerin kutulanması gerektiği için bunun bazı performans değerlendirmeleri vardır. Tabii ki, derleme zamanı türünün doğruluğunun faydaları, tip silme genel sersemliği ve geriye dönük uyumluluk konusundaki takıntılı odaktan daha ağır basar.

56
ChaosPandion

Daha önce verilen yanıtların Java dili, JVM ve Java Sınıf Kütüphanesi) kombinasyonuna odaklandığını gözlemleyin.

Java'nın dili ile ilgili olarak Java'nın jenerikleriyle ilgili yanlış bir şey yoktur. C # vs Java generics bölümünde açıklandığı gibi, Java'nın jenerikleri dil düzeyinde oldukça iyidir1.

Yetersiz olan, JVM'nin bazı önemli sonuçları olan jenerik ilaçları doğrudan desteklememesidir:

  • sınıf Kitaplığı'nın yansıma ile ilgili bölümleri, Java dilinde kullanılabilen tam tür bilgileri gösteremez
  • performans cezası var

Dil her zaman JVM ile hedef olarak ve Java Sınıf Kitaplığı çekirdek kütüphane olarak) derlendiğinden, yaptığım ayrım bilgiçlik tasavvurudur.

1 Tip çıkarımını genel durumda kararsız hale getirdiğine inanılan joker karakterlerin olası istisnası ile. Bu C # ve Java çok sık bahsedilmeyen jenerikler arasında büyük bir farktır. Teşekkürler, Antimon).

26
Roman Starkov

Olağan eleştiri, eksikliktir. Yani çalışma zamanında nesneler genel argümanları hakkında bilgi içermezler (her ne kadar bilgi hala alanlar, yöntem, yapıcılar ve genişletilmiş sınıf ve arayüzler üzerinde mevcut olsa da). Bu, ArrayList<String> İfadesini List<File> Öğesine atabileceğiniz anlamına gelir. Derleyici size uyarı verir, ancak bir ArrayList<String> Öğesinin Object referansına atar ve ardından List<String> Öğesine gönderirseniz de sizi uyarır. Uzayanlar, jeneriklerle muhtemelen döküm yapmamalısınız, gereksiz veriler ve elbette geriye dönük uyumluluk olmadan performans daha iyidir.

Bazı insanlar genel argümanlar (void fn(Set<String>) ve void fn(Set<File>)) temelinde aşırı yükleyemeyeceğinizden şikayet ederler. Bunun yerine daha iyi yöntem adları kullanmanız gerekir. Aşırı yükleme statik, derleme zamanı sorunu olduğundan, bu aşırı yüklemenin yeniden adlandırılması gerekmeyeceğini unutmayın.

İlkel türler jeneriklerle çalışmaz.

Joker karakterler ve sınırlar oldukça karmaşıktır. Çok faydalılar. Java tercih edilemezlik ve söyleme-sorma arabirimleri tercih ederse, kullanım tarafı jenerikleri yerine bildirim tarafı daha uygun olacaktır.

13

Java jenerikleri emer çünkü aşağıdakileri yapamazsınız:

public class AsyncAdapter<Parser,Adapter> extends AsyncTask<String,Integer,Adapter> {
    proptected Adapter doInBackground(String... keywords) {
      Parser p = new Parser(keywords[0]); // this is an error
      /* some more stuff I was hoping for but couldn't do because
         the compiler wouldn't let me
      */
    }
}

Yukarıdaki koddaki her sınıfı, jeneriklerin aslında genel sınıf parametreleri olması gerektiği gibi çalışmasını sağlamak için kasaplamanız gerekmez.

10
davidk01
  • hiçbir amaca hizmet etmeyen eksik genel parametreler için derleyici uyarıları dili anlamsız bir şekilde ayrıntılı hale getirir, örneğin public String getName(Class<?> klazz){ return klazz.getName();}

  • Generics dizilerle Nice oynamayın

  • Kayıp tip bilgisi, yansımayı döküm ve koli bandının karmaşaya dönüştürür.

5
Steve B.

Sanırım diğer cevaplar bunu bir dereceye kadar söyledi, ama çok net değil. Jeneriklerle ilgili sorunlardan biri, yansıtma sürecinde jenerik türlerin kaybedilmesidir. Yani mesela:

List<String> arr = new ArrayList<String>();
assertTrue( ArrayList.class, arr.getClass() );
TypeVarible[] types = arr.getClass().getTypedVariables();

Ne yazık ki, döndürülen türler, arr'ın genel türlerinin String olduğunu söyleyemez. İnce bir fark, ama önemli. Arr çalışma zamanında oluşturulduğundan, genel türler çalışma zamanında silinir, böylece bunu anlayamazsınız. Bazılarının belirttiği gibi ArrayList<Integer> Yansıma açısından ArrayList<String> İle aynı görünüyor.

Bu Generics kullanıcısı için önemli olmayabilir, ancak diyelim ki kullanıcının bir örneğin somut jenerik türlerini nasıl ilan ettiği hakkında süslü şeyler bulmak için yansıma kullanan bazı süslü bir çerçeve oluşturmak istedik.

Factory<MySpecialObject> factory = new Factory<MySpecialObject>();
MySpecialObject obj = factory.create();

Diyelim ki genel bir fabrikanın MySpecialObject örneği yaratmasını istedik, çünkü bu örnek için beyan ettiğimiz somut genel tür. Fabrika sınıfı, bu örnek için bildirilen somut türü bulmak için kendisini sorgulayamaz çünkü Java onları sildi.

.Net'in jeneriklerinde bunu yapabilirsiniz çünkü çalışma zamanında nesne genel türlerini bilir, çünkü derleyici ikiliye uymuştur. Silme işlemleriyle Java bunu yapamazsınız.

5
chubbsondubs

Jenerikler hakkında birkaç iyi şey söyleyebilirim, ama soru bu değildi. Çalışma zamanında mevcut olmadıklarından ve dizilerle çalışmadığından şikayet edebilirim, ancak bundan bahsedildi.

Büyük bir psikolojik sıkıntı: Bazen jeneriklerin işe yarayamayacağı durumlara giriyorum. (Diziler en basit örnek.) Ve jeneriklerin işi yapamayacağını mı yoksa sadece aptal mı olduğumu anlayamıyorum. Bundan nefret ediyorum. Jenerik gibi bir şey her zaman çalışmalı. Her seferinde Java dilini kullanarak istediğimi yapamıyorum, ( biliyorum sorun benim ve sadece devam edip etmediğimi biliyorum iterek, sonunda oraya geleceğim. Jenerikler ile, çok ısrarlı olursam, çok zaman harcayabilirim.

Ama asıl sorun jeneriklerin çok az kazanç için çok fazla karmaşıklık katmasıdır. En basit durumlarda, bir Apple araba içeren bir listeye eklememi engelleyebilirim. İçinde bir çocuk bulunan bir çocuk koltuğu olan bir araba ekleyin, derlemenin sadece bebek şempanzeleri içeren çocuk koltukları olan otomobiller için olduğunu derleme zamanı uyarısına ihtiyacım var mı?.

Genel kod çok fazla kelime ve karakter içerebilir ve fazladan yer kaplayabilir ve okunması daha uzun sürebilir. Doğru çalışmak için tüm bu ekstra kodu almak için çok zaman harcayabilirsiniz. Böyle olunca kendimi zeki hissediyorum. Ben de kendi saatimi birkaç saat veya daha fazla boşa harcadım ve başka hiç kimse kodu anlamak mümkün olacak merak etmek zorunda. Kendimden daha az akıllı olan veya boşa harcayacak daha az zamanı olan insanlara bakım için teslim etmek istiyorum.

Öte yandan (Orada biraz yaralandım ve biraz denge sağlamaya ihtiyacım var), basit koleksiyonları ve haritaları kullanırken güzel yazıldığında ekler, koyar ve kontrol edilir ve genellikle koda çok fazla karmaşıklık eklemez ( eğer birisi başka koleksiyonu veya haritayı yazar) . Ve Java bu konuda C # daha iyidir. Kullanmak istediğim C # koleksiyonlarının hiçbiri jenerikleri işlemez gibi görünüyor. (Koleksiyonlarda garip lezzetler olduğunu itiraf ediyorum.)

1
RalphChapin