2009-04-14 29 views
45

Her birinde oluşturduğum sistemde bulunan bir türü temsil eden bir Sınıflar dizisi oluşturmak istiyorum. İlgili tüm sınıflar ortak bir süper sınıfın alt sınıflarıdır. Bu yüzden yapmak istiyorum:Jenerikleri bir dizi Sınıf ile nasıl kullanırım?

Class<? extends SuperClass>[] availableTypes = { SubClass1.class, SubClass2.class }; 

Bu bana hata veriyor: Ben sağ taraftaki dizinin oluşturulmasını nitelemek çalışırsanız

Cannot create a generic array of Class<? extends SuperClass>. 

Ben aynı mesajı almak başlatma:

:

Class<? extends SuperClass>[] availableTypes = Class<? extends SuperClass>[] { SubClass1.class, SubClass2.class }; 

Ben jenerik nitelikleri ortadan eğer derlemek için kodu alabilirsiniz 210

Ancak, sonra da şu genel uyarıları alıyorum:

Sınıf bir türdür. Jenerik tip Sınıfına yapılan referanslar parametrelendirilmelidir.

deniyorum; Deniyorum! :) Ayrıca, bu noktada, bu bir uyarıya sebep olmasa bile, tanımlamaya çalıştığım arabirimin bir parçasını kaybediyorum. Sadece bir dizi keyfi sınıf döndürmek istemiyorum; Belirli bir SuperClass'ın tüm alt sınıfları olan bir dizi dersi geri vermek istiyorum!

Eclipse, generics bildirimlerini düzeltmek için hangi parametrelerin kullanılacağını bulmak için oldukça güçlü araçlara sahiptir, ancak bu durumda, Class ile uğraşırken yaptığınız gibi düşmektedir. Sunulan "Genel Türlü Argümanlar" prosedürü, kodu değiştirmez ve uyarıyı bırakmaz.

yerine Bir Koleksiyon kullanarak bu geçici bir çözüm başardı:

List<Class<? extends SuperClass>> availableTypes = new List<Class<? extends SuperClass>>(); 

Ama diziler ile bunu yapmanın doğru yolu nedir?

cevap

22

Biraz bozguncu gibi görünüyor, ama böyle sorunlar tam çoğu insan dizileri ve jenerikleri karıştırma önlemek sebebi vardır. Jeneriklerin uygulanma biçimi nedeniyle (type erasure), diziler ve jenerikler asla birlikte iyi çalışmayacaktır.

iki geçici çözüm de:

  • çalışan bir toplama (örneğin ArrayList<Class<? extends SuperClass>>), sadece aynı zamanda bir dizi kullanarak Çubuk ve genişleme sağlar.
  • kullanımını haklı bir yorum ile birlikte diziyi oluştururken kod üzerinde bir @SuppressWarnings("unchecked") ek açıklama koyun.
2

Sorun, genel bir türden dizi oluşturmanın yasadışı olması. Bunu elde etmenin tek yolu, diziyi oluştururken genel türe göre döküm yapmaktır, ancak bu çok iyi bir çözüm değildir. (Sadece bir tane oluşturmaz, bu kullanım jenerik dizi mümkün olduğunu unutmayın. this question bakınız)

Neredeyse her zaman zaten yerine Dizilerin listelerini kullanarak olmalı, bu yüzden zaten iyi çözüm geldi düşünüyorum .

14

bunu kullanın sözdizimi: Eğer dizide SuperClass uzanmayan bir türü için Class nesne dahil olabilir çünkü

Class<? extends SuperClass>[] avail = new Class[] { SubClass1.class, ... }; 

Bu haklı bir şekilde size bir "kontrolsüz" uyarı vermek ve olacaktır.

11

diziler ile bunu yapmanın doğru yolu bir Koleksiyonu ile yapmaktır. Afedersiniz! Karmaşık nedenlerden ötürü, diziler jeneriklerle iyi oynamaz. Diziler, genel nesnelere göre farklı bir kovaryans modeline sahiptir ve sonuçta karşılaştığınız problemlere neden olur. Örneğin, diziler, ancak (normalde) jenerik nesnelerle, yasal olarak bunu yapabilirsiniz:

Object[] myArray = new String[5]; 

Eğer bunu yapamaz ise: Daha fazla ayrıntı istiyorsanız

LinkedList<Object> myCollection = new LinkedList<String>(); 

görebilirsiniz simonn söylediği gibi mükemmel Generics FAQ

dan Arrays In Java Generics sayfa, ayrıca sadece oldukları gibi diziler kullanabilir ve uyarıları susturmaya @SuppressWarnings("unchecked") kullanabilirsiniz. Bu çalışır, ancak jeneriklerin size sağlayabileceği tip güvenliği yoktur. Endişelendiğiniz bir performans varsa, sadece bir ArrayList kullanın, böylece bir dizi etrafında ince bir sarıcı kullanıyorsunuz, ancak jeneriklerin sağladığı tüm güvenlik garantileriyle.

+1

Kovaryansı! Kötü söz dedin! –

4

But what's the right way to do this with arrays?

Bunu yapmanın güvenli bir yolu yoktur; Koleksiyonu kullanarak doğru yaklaşımdır. Nedenini görmek için buna izin verilip verilmediğini hayal edin. Böyle bir durum olabilir:

// Illegal! 
Object[] baskets = new FruitBasket<? extends Citrus>[10]; 

// This is okay. 
baskets[0] = new FruitBasket<Lemon>(); 

// Danger! This should fail, but the type system will let it through. 
baskets[0] = new FruitBasket<Potato>(); 

tip sistem diziye ekleniyor bir sepet tipi FruitBasket<? extends Citrus> veya alt tipin olup olmadığını algılamak gerekiyor. Bir FruitBasket eşleşmiyor ve ArrayStoreException ile reddedilmeli. Ama hiçbir şey olmadı!

JVM, tür silme işleminden ötürü, yalnızca dizinin çalışma zamanı türünü görebilir. Çalışma zamanında, eşleştiğinden emin olmak için dizi türünü eleman türüyle karşılaştırmalıyız. Dizinin çalışma zamanı bileşeni türü, silme işleminden sonra FruitBasket[]; Aynı şekilde, elemanın çalışma zamanı türü FruitBasket'dur. Hiçbir sorun tespit edilmeyecek - ve bu yüzden bu tehlikeli.

0

güvenli ve kontrolsüz döküm uyarı ile yazın değil:

Class<? extends SuperClass>[] availableTypes = 
    (Class<? extends SuperClass>[]) 
    (new Class[]{ SubClass1.class, SubClass2.class }); 
İlgili konular