Java jenerikleri örneklerle kısa biçimde açıklanmıştır

Daha fazla bilgi için lütfen bu SSS’ye'ye bakın:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#SECTION1

Kısaca SSS’'de bazı önemli noktaları burada bulabilirsiniz.

Örnek (genel türü):

sınıf Çift<X,Y> { 
  önce özel X;
  özel Y saniye;   genel Çift(X a1, Y a2) {
    birinci = a1;
    ikinci = a2;
  }
  public X getFirst() { önce dön; }
  public Y getSecond() { ikinci dönüş; }
  public void setFirst(X arg)  { ilk = arg; }
  public void setSecond(Y arg) { saniye = arg; }
}

sınıf Çift iki tip parametresi vardır X Ve e .  Genel tür değiştirildiğinde bunların yerini tür bağımsız değişkenleri alır. Çift somutlaştırılmıştır. Mesela beyannamede Çift<Dize, Tarih> tür parametresi X type argümanı ile değiştirilir Sicim Ve e şununla değiştirilir:  Tarih .
Tanımlayıkların Kapsamı X Ve e öyle sınıfın tam tanımı.  Bu kapsamda iki tip parametre X Ve e türlermiş gibi kullanılmışlar (bazı szırımlarla). Yukarıdaki örnek türü parametreleri, örnek yöntem bağımsız değişkenleri ve dönüş türleri, örnek alan türleri olarak kullanılır.
Tür parametreleri şişılarla bükülebilir. Sınılar, tip parametresinin teşmel tehgi unbeminayen türdeki medodole erişimini sağlar. Örneğimizde bilimenayen türdeki metözülü çığlığı yapmıyoruz. X Ve e . Bu nedenle iki tür parametreleri sınırlıdır.

Örnek (bazı parametreler türü):

genel geçersiz printPair( Çift<Dize, Uzun> çift) {
  System.out.println("("+pair.getFirst()+",+pair.getSecond()+")");
} Çift<Dize, Uzun> sınır = yeni Çift<Dize, Uzun> ("maksimum",1024L);
printPair(limit);

Örnek (joker karakterle parametrelendirilmiş tür):

genel geçersiz printPair( Çift<?,?> çift) {
  System.out.println("("+pair.getFirst()+",+pair.getSecond()+")");
} Çift<?,?> sınır = yeni Çift<Dize, Uzun> ("maksimum",1024L);
printPair(limit);

Genel bir türün tüm örnekleri aynı çalışma zamanı türü temsilini, yani ham türün temsilini paylaşır. Örneğin, genel bir türün örnekleri Liste , örneğin Liste<Tarih> , List<String> , Liste<Long> vb. derleme zamanında farklı statik türlere sahiptir ancak aynı dinamik türe sahiptir Liste iş zamanında.

Bir oyuncu kadrosunun iki görünümü:

  • derleme zamanında derleyici tarafından gerçekleştirilen statik tip kontrolü ve
  • çalışma zamanında sanal makine tarafından gerçekleştirilen dinamik tür kontrolü.

Statik kısım, başarılı olamayan saçma sapan yayınları (ör. Sicim O Tarih veya itibaren List<String> O Liste<Tarih> .

Dinamik aralık, şilma zamandi tür bilgsini kılızır ve şilma samında bir tür kontrol çalışır.  Artırmak ClassCastException nesnenin dinamik türü, dönüşümün hedef türü (veya hedef türünün bir alt türü) değilse. Dinamik parçalı oyuncu kadrosuna örnek olarak şunlar verilebilir: Nesne O Sicim veya itibaren Nesne O List<String> .  Bunlar, bir üst tipten bir alt tipe kadar üşaya dürü olanlardır.

Türün bazı parametreleri şunlardır: List<String> , Harita<Dize, Tarih> , ama değil Liste<? Number>'yi genişletiyor veya Harita<String,?> .

Bazen ki List<Object> bir süper tip olurdu List<String> , Çünkü Nesne bir süper türüdür Sicim .  Bu beklenti diziler için böyle bir ilişkinin mevcut olmasından kaynaklanmaktadır:  Nesne[] bir süper türüdür Sicim[] , Çünkü Nesne bir süper türüdür Sicim . (Bu tür bir ilişki şu şekilde bilinir: kovaryans .) Bileşen türlerinin süper alt tür ilişkisi, karşılık gelen dizi türlerine kadar uzanır. Genel türlerin örnekleri için böyle bir tür ilişkisi mevcut değildir. (Parametreli tipler Olumsuz kovaryant.)

Aînî genel türun semplari Özgür bir üst alt tür sülüşinin bulunmamasın varışınızdarınızın.  İşte bir örnek.

Örnek:

void printAll(ArrayList<Object> c) {
  için (Nesne o : c) 
    System.out.println(o);
} ArrayList<String> listesi = new ArrayList<String>();
... listeyi doldur ...
printAll(liste);   // hata

A DiziList<String> nesne, talep eden bir yönteme argüman olarak aktarılamaz. DiziList<Object> çünkü iki tür aynı genel türün örnekleridir, ancak farklı tip çoğalmaları vardır ve bu birriiley högüttındırlar.

Somut parametreli türler, genel bir türün somut sempleridir.  Neredeyse benser tiplerdir; yalnızca birkaç kısıtlama vardır.  KULLANILAMAZ'ın aşağıdaki amaçları:

  • dizilerin oluşturulması için
  • istisna işlemede
  • bir sınıfta
  • bir şekilde örneği ifade

Türü somut parametreli tür olan ıldımı tutan diziler yasa dışıdır.

Örnek (geçersiz dizi tyru):

statik boşluk testi() {
  Çift<Tamsayı,Tamsayı>[] intPairArr = yeni Çift<Tamsayı,Tamsayı>[10] ; // hata
  addElements(intPairArr); 
  Pair<Tamsayı,Tamsayı> çift = intPairArr[1];
  Tamsayı i = çift.getFirst();
  çift.setSecond(i);
}
statik void addElements ( Nesne[] objArr) {
  objArr[0] = new Pair<Tamsayı,Tamsayı>(0,0);
  objArr[1] = new Pair<String,String>(""");      // ArrayStoreException ile başarısız olmalı
}

Derleyici, bileşen türü somut parametreli tür olan dizilerin oluşturulmasını yasaklar; Çift<Tamsayı,Tamsayı> bizim örneğimizde.  Önceki girişte derleyicinin bir sertifikayı nitelendirmesinin neden makul olduğunu tartıştık. Çift<Tamsayı,Tamsayı>[] yasadışı olarak.  Temel sorun, derleyici ve çalışma zamanı sisteminin bir dizinin bir dizi olmasını sağlaması gerektiğidir. homojen aynı türden elemanların dizisi.  Tür kontrollerinden biri, yani çalışma zamanında sanal makine tarafından gerçekleştirilen dizi-depolama-kontrol, rahatsız edici bir yabancı öğenin eklenmesini tespit etmekte başarısız olur. Örnekte ikinci ekleme addElements yöntem başarısız oldu, çünkü bir dizi integrali bir çift dize ekliyorlardı, izba beklendiği gibi başarısız olmuyor. Bunun kızışları bir önceki yazda kışlanmıştı.

Türü somut parametreli tür olan idılım tutan dizileri kullanamayansak türü somut olarak çözülebilir olarak ne kılılır?

Akla gelebilek 3 geçici çözüm ele alınarak:

  • ham tür dizisi
  • sınırsız joker karakter parametreli tür dizisi
  • dizi yerine koleksiyon

Somut parametreli tetirin dizileri yasa dışı olsa da, somut parametreli tetirin izin verir.

Joker karakter parametreli tür, en az bir tür tür tür tür tür tür tür tür tür, joker karakter tülşı genel bir türün tısradırır.  Joker karakter parametrelendirilmişin sempların seklerin şıldın: Koleksiyon<?> , Liste<? Number>'yi genişletiyor , Karşılaştırıcı<? süper String> Ve Çift<String,?> . Joker karakterle parametrelendirilmiş tür, genel bir türün somut örneklemelerini içeren bir tür ailesini belirtir.  Kullanılan joker karakter türü, hangi somut parametreli türlerin aileye ait olduğunu belirler.  Örneğin, joker karakter parametreli tür Koleksiyon<?> tüm örneklerin ailesini belirtir Koleksiyon tür argümanından bağımsız olarak arayüz.  Joker karakter parametreli tür Liste<? Number>'yi genişletiyor öğe türünün bir alt türü olduğu tüm liste türlerinin ailesini belirtir  Sayı .  Joker karakter parametreli tür Karşılaştırıcı<? süper String> tüm örneklerin ailesidir Karşılaştırıcı süper türleri olan tür bağımsız değişkeni türleri için arayüz Sicim.

Joker karakterle parametrelendirilmiş tür, normal anlamda bir tür değildir (parametreleştirilmemiş sınıftan/arabirimden veya ham türden farklı).

Yazmak için joker karakterle parametrelendirilmiş türler kullanılabilir (parametreleştirilmemiş sınıflar ve arayüzler gibi):

  • argüman ve dönüş yöntemleri olarak
  • bir alanın türü veya yerel referans değişkeni olarak
  • bir dizinin bileşen türü olarak diğer parametreli türlerin tür bağımsız değişkeni olarak
  • yayınlarda hedef türü olarak

Yalnızca türler genel olamaz, aynı zamanda genel olarak da olabilir. Statik ve statik olmayan yöntemler de mevcuttur. Resmi tür parametrelerinin sözdizimi sözdizimi, genel türerin sözdizimine beser. Tür parametresi bibhi açılı ayraçlarla gırınarızımtır ve medözün turşır ıtüründen önce darışır. Sözdizimi ve anlamı, genel bir ıtürun tür parametre listesiyle sağındır.

İşte genel bir örnek maksimum Bilinmeyen türden öğelerden oluşan bir koleksiyondaki en büyük değeri hesaplayan yöntem A .

Örnek (genel bir yöntem):

sınıf Koleksiyonlar {
  genel statik <A Karşılaştırılabilir<A>> A'yı genişletir max(Koleksiyon< A > xs) {
    Yineleyici< A > xi = xs.iterator();
    A w = xi.sonraki();
    while (xi.hasNext()) {
      A x = xi.sonraki();
      if (w.compareTo(x) < 0) w = x;
    }
    w'ye dönüş;
  }
} 

Bu maksimum yöntemin adında bir tür parametresi vardır A .  Yöntemin üzerinde çalıştığı koleksiyonun öğe türü için yer tutucudur. type parametresinin bir sınırı vardır; alt türü olan bir tür olmalıdır Karşılaştırılabilir<A>

Örnek (aynı genel türden, bu sefer ile sınırlar):

genel arayüz Karşılaştırılabilir<T> {
  public int CompareTo(T arg);
}
genel sınıf TreeMap<Key Karşılaştırılabilir<Key>'yi genişletir ,Veri>{
  özel statik sınıf Entry<K,V> {
     K tuşu;
     V değeri;
     Giriş<K,V> sol = null;
     Giriş<K,V> sağ = null;
     Giriş<K,V> üst öğe;
  }
  özel geçici Entry<Key,Data> root = null;
  ...
  özel Entry<Key,Data> getEntry(Anahtar anahtarı) {
     Giriş<Key,Data> p = kök;
     Anahtar k = anahtar;
     while (p != null) {
       int cmp = k. CompareTo(p.key) ; 
       eğer (cmp == 0)
         p'yi döndür;
       else if (cmp < 0)
         p = p.sol;
       başka 
         p = p.sağ; 
     }
     boş değer döndür;
  }
  public boolean includeKey(Anahtar anahtarı) {
     return getEntry(anahtar) != null;
  }
  ...
}

Yukarıdaki örnekte type parametresi Anahtar sınırı var Karşılaştırılabilir<Anahtar> .  Bir sınırın belirtilmesinin iki etkisi vardır:

  • Sınırın belirttiği yöntemlere erişim sağlar .  Örnekte, sınır Karşılaştırılabilir<Anahtar> erişim sağlar karşılaştır uygulamamızda kullanmak istediğimiz yöntem Ağaç Haritası sınıf.
  • Genel türü başlatmak için yalnızca “ serisindeki ” türleri kullanılabilir.   Örnekte, aşağıdaki gibi parametreli bir tür Ağaç Haritası<Numara,Dize> türü nedeniyle reddedilecektir. Sayı bir alt türü değildir Karşılaştırılabilir<Numara> .  Gibi parametreli bir tür Ağaç Haritası<Dize, Dize> kabul edilir, çünkü String türü sınırlar içindedir, yani bir alt türdür. Karşılaştırılabilir<String> .

İç ve iç türler de dahil olmak üzere ısılı tüm klasikler, arayüzler ve numaralandırmanın tetiklendiği, tür parametresi ışığı olarak kullanılabilir.  Tür parametrelerinin ışığı olarak ne ilkel türler ne de dizi türü keselmakaz.

Örnekler (uç parametre limitleriyle ilgili):

sınıf X0 <T genişliyor int > { ... }      // hata
sınıf X1 <T genişletiliyor Nesne[] > { ... } // hata
sınıf X2 <T genişliyor Sayı > { ... }
X3 sınıfı <T genişletiliyor Sicim > { ... }
X4 sınıfı <T genişletiliyor Çalıştırılabilir > { ... }
sınıf X5 <T genişletiliyor Konu.Durum > { ... }
sınıf X6 <T genişletiliyor Liste > { ... }
sınıf X7 <T genişletiliyor List<String> > { ... }
sınıf X8 <T genişletiliyor Liste<? Number>'yi genişletiyor > { ... }
sınıf X9 <T genişletiliyor Karşılaştırılabilir<? süper Numara> > { ... }
X10<T sınıfı genişletiliyor Harita.Giriş<?,?> > { ... }

Kod örneği, aşağıdaki gibi ilkel türlerin olduğunu gösterir: int ve dizi türleri gibi Nesne[] tür parametresinin kırılmasına izin verilmez.

Örneğin sınıf türleri Sayı veya Sicim ve arayüz türleri gibi Çalıştırılabilir .

Enum türleri, örneğin Konu.Durum tür parametresine bağlı olarak da izin verilir. Konu.Durum tür parametresi kırışı olarak ışıltılı iç içe geçme sırasının birşdirir.  Statik olyan iç tiplere de izin verir.

Ham türlere, tür parametreleri olarak izin verir; Liste bir şakşırtır.

Parametreli tiplere, begekenseler gibi somut parametreli tipler de dahil olmak ısımın, tip parametresi gışır olarak izin verir: List<String> , sınırlı joker karakter parametreli türler gibi Liste<? Number>'yi genişletiyor Ve Karşılaştırılabilir<? süper Uzun> ve sınırsız joker karakter parametreli türler gibi Harita.Giriş<?,?> .  Joker karakterle parametrelendirilmiş bir tür olan bir gırır, joker karakterinin behirlendiği tür ailisine ait tüm türlere tür tür tür tür sındığını olarak izin verir.  Joker karakteriyle parametrelendirilmiş tür kırırı, alanlara ve medodole yalnızca sınırlı erişime izin verir; kısıtlamalar joker karakteri

Örnek:

X< sınıfı T List<'yi genişletiyor mu? Number>'yi genişletiyor > {
  genel void someMethod(T t) {
    t.add(yeni Uzun(0L));    // hata
    Sayı n = t.remove(0);
  }
}
sınıf Testi {
  public static void main(String[] args) {
     X<ArrayList< Uzun >> x1 = yeni X<ArrayList<Long>>(); 
     X<ArrayList< Sicim >> x2 = yeni X<ArrayList<String>>(); // hata
  }
}

Türün referans değişkenleri T (tip parametresi), bir joker karakterin dağıldığı (sınırlanan tür parametresi) referen sılıları gibi ele alınır.  Örneğimizde sonuç olarak, derleyicinin tip parametresinin temsal teghidi “bilinmeyen” tipi bir aralık alan metödösin föjlmasıni reddetmesidir; Liste.ekle üçük şışırı, üst şırırı olan joker karakter parametreli bir türdür.
bu çok önemli Liste<? Number>'yi genişletiyor Tür bağımsız değişkenleri olarak kullanılabilecek türleri belirler. Derleyici, tür ailesine ait olan tüm tür bağımsız değişkenlerini kabul eder. Liste<? Number>'yi genişletiyor yani tüm alt türleri Liste alt türü olan bir tür argümanıyla Sayı .

Bir tür parametresi başka bir tür parametresinin kırırı olarak beşiktaş.

Örnek:

sınıf Üçlü <T> {
  özel T fst, snd, trd;
  halka açık < sen T'yi uzatır , V T'yi uzatır , W T'yi uzatır > Üçlü(U arg1, V arg2, W arg3) {
    fst = arg1;
    snd = arg2;
    trd = arg3;
  }
}

Bu örnekte type parametresi T parametreli sınıfın türü parametrelerinin sınırı olarak kullanılır sen ,  V Ve W o klassin parametreli samskar medsvetsinin.

Tür parametrelini tür parametrelini olarak tür parametrelerinin geyarları olarak kullanma tür parametrelerinin Işındar überatlar Işındarın, iç içe bir tyrun genel bir tür içinde tahnılındangı veya yerel bir klasik genel bir yöntem içinde tahni edildiği yer alır.  Aynı tip parametre bölümünde ise bir tip parametresinin başka bir tip parametresine büdü olarak veğlerini bile izin verrır.

Bir klassig olan gehir, tüm ortak bädelerine, yani ortak alanlara, medodolele ve iç içe goçem türlerine öçinak sağlar. Sınırın bir alt klasınınınınının bir alt klasının ınının bir alt klasının ınının ınılı ınının ıyapıcılarının ınılımez ınılılemez sınıflarının ınının ınılı ınının ınının ınının bir alt klasının ınının dayanmalarının ınılımez.

Örnek (bir tür parametresinin kırışı olarak ısaklanın bir kalasın):

kamu sınıfı Süper Sınıf {     // statik üyeler
    public enum EnumType {THIS, BU}
    genel statik Nesne staticField;
    public static void staticMethod() { ... }

    // statik olmayan üyeler
    genel sınıf İç Sınıf { ... }
    public Object nonStaticField;
    public void nonStaticMethod() { ... }

    // yapıcılar
    genel Süper Sınıf() { ... }

    // özel üyeler
    özel Nesne PrivateField; 

    ...
}

genel final sınıfı SomeClass<T genişletiliyor Süper Sınıf > {
    özel T nesnesi;
    public BazıSınıflar(T t) { nesne = t; } 

    public String toString() {
        geri dönmek
         "statik iç içe tür    : "+T.EnumType.class+"\n" 
        +"statik alan          : "+T.staticField+"\n"
        +"statik yöntem         : "+T.staticMethod()+"\n"
        +"statik olmayan iç içe tür: "+T.InnerClass.class+"\n"
        +"statik olmayan alan      : "+object.nonStaticField+"\n"
        +"statik olmayan yöntem     : "+object.nonStaticMethod()+"\n"
        +"yapıcı           : "+(yeni T())+"\n"                    // hata
        +"özel üye        : "+object.privateField+"\n"          // hata 
        ;
    }
}

Sınırlı Süper Sınıf iç içe geçmiş türlerine, statik alanlarına ve yöntemlerine ve statik olmayan alan ve yöntemlerine erişim sağlar.  Yalnızca yapıcıya erişilemez.  Bunun nedeni yapıcıların miras alınmamasıdır. Her alt sınıf kendi kurucularını tanımlar ve üst sınıfın kurucularını desteklemesi gerekmez.  Dolayısıyla bir alt sınıfın olacağının garantisi yoktur. Süper Sınıf üst sınıfla aynı kurucuya saatif olacak.

Bağlam bulundu Enum<E, Enum<E>>'yi genişletiyor “görünüşe göre beyanı Numaralandırma paketteki sınıf java.lang :

genel soyut sınıf Enum<E, Enum<E>>'yi genişletiyor {
  ...
}

Tür Numaralandırma Tüm numarandırmının türirinin ortak temel klasıdır.  Java’da ozellikle bir numaralandırma ıtürü Renk bir sınıfa çevrildi Renk bu uzanır Enum<Color> . Süper sınıfın amacı Numaralandırma Tüm numaralandırma türünde ortak olan funkselliği sağlamaktır.

Işte klasik bir taslağı Numaralandırma :

genel soyut sınıf Enum< e Enum<E>>'yi genişletir Karşılaştırılabilir<'yi uygular e >, Serileştirilebilir {
  özel son Dize adı;
  genel son Dize adı() { ... }   özel final int ordinal;
  genel final int ordinal() { ... }

  korumalı Enum(Dize adı, int sıra) { ... }

  public String           toString() { ... }
  genel final boole eşittir (Diğer nesne) { ... }
  genel final int hashCode() { ... }
  korumalı son Nesne clone(), CloneNotSupportedException'ı atar { ... }
  genel final int CompareTo( e o) { ... }

  genel final Class< e > getDeclaringClass() { ... }
  public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { ... }
}

Deklarasyondaki şaşırtıcı özellik ” Enum<E, Enum<E>>'yi genişletiyor OZYX0Yeni tanımlanmış sınıf gerçeği Numaralandırma ve yeni tanımlanan tür parametresi e aynı tür parametrenin sınırında görünür.  Bu şu anlama gelir: Numaralandırma türün alt türlerinden biri için başlatılması gerekir.  Bunun neden anlamlı olduğunu anlamak için her numaralandırma türünün bir alt türe çevrildiğini düşünün. Numaralandırma .

Işte yapmak enum type Renk :

numaralandırma Renk {KIRMIZI, MAVİ, YEŞİL}

Derleyici bunu aşağıdaki sınıfa çevirir:

genel final dersi Renk uzanır Enum<Color> {
  public static final Renk[] değerler() { return (Renk[])$VALUES.clone(); }
  public static Color valueOf(Dize adı) { ... }   özel Color(String s, int i) { super(s, i); }

  genel statik son Renk KIRMIZI;
  genel statik son Renk MAVİ;
  genel statik son Renk YEŞİL;

  özel statik son Renk $VALUES[];

  statik {
    KIRMIZI = yeni Renk("KIRMIZI", 0);
    MAVİ = yeni Renk("MAVİ", 1);
    YEŞİL = new Renk("YEŞİL", 2);
    $DEĞERLER = (yeni Renk[] { KIRMIZI, MAVİ, YEŞİL });
  }
}

Mirasın etkisi vardır Renk type, uygulanan tüm yöntemleri miras alır Enum<Color> .  Bunlar arasında karşılaştır Yöntem.  Renk. karşılaştır yöntem muhtemelen bir almalı Renk bir argüman olarak.  Bunu gerçekleştirmek için sınıf Numaralandırma geneldir ve Enum.compareTo yöntem alır Numaralandırma ‘in tür parametreleri e bir argüman olarak.  Sonuç olarak yazın Renk türetilmiş Enum<Color> miras alır karşılaştır alan bir yöntem Renk ve çoğalması, tam olarak olsisi diliği gibi.
Bildiryi incelersek “ Enum<E, Enum<E>>'yi genişletiyor “Bu modelini çeşitli yönlerde görebiliyoruz.

Öncelikle tanımlanan tür parametresinin tyurun kendisi tışı var: “ Numaralandırma <E genişliyor Numaralandırma <E>> “. Türün yalnızca alt türlerin kullanılmasına izin verir Numaralandırma tür bağımsız değişkenleri olarak izin verilir. (Teorik olarak yazın Numaralandırma olduğu gibi kendi kendine örneklenebilir Enum<Enum> (Fakat bu kesinlikle amaçlanmamıştır.)

İkinisi, parametreye büdü türün parametreli tür tülşı gücüükı vardır. Numaralandırma <E> type parametresini kullanan e sınırın tür argümanı olarak. Bu bildirim, bir alt tür ile bir örnek oluşturma arasındaki kalıtım ilişkisinin garanti altına alınmasını sağlar. Numaralandırma formdadır X, Enum<X>'yi genişletir “. Gibi bir alt tür “ X, Enum<Y>'yi genişletir ” tipi bağımsız değişken rapor edilmiyor e sınırlar içinde olmayacak; yalnızca alt türleri Enum<X> ışıklar ışığımdır.

Üçüncüsü şu gerçek var Numaralandırma öncelikle geneldir.  Bu, bazı sınıf yöntemlerinin olduğu anlamına gelir. Numaralandırma bir argüman alın veya bilinmeyen türde bir değer döndürün (ya da bilinmeyen bir türe bağlı). Zaten bildiğimiz gibi bu bilinmeyen tür daha sonra bir alt tür olacak X ile ilgili Enum<X> .  Bu nedenle, parametreli tipte Enum<X> , bu yöntemler alt türü içerir X ve alt türe miras alınırlar X .  karşılaştır yöntem böyle bir yöntemin saşıdırır; üst kläsigtan her alt kläsiga miras alındır ve her sludda alt kläsig bir imzaya sözüt.

Özetlemek köllorse, bildirim “ Enum<E, Enum<E>>'yi genişletiyor “şu çözülebilir: Numaralandırma yalnızca alt türleri için örneklenebilen genel bir türdür ve bu alt türler, bazıları alt türe özgü argümanlar alan (veya başka şekilde alt türe bağlı olan) bazı yararlı yöntemleri miras alır.

Sınıfların Alt Sınır Tipi Parametreleri

Tür parametrelerinin aşağıdaki gibi birkaç sınırı olabilir: Box<T sınıfı Number>'yi genişletir {...} . Ancak bir tür parametresinin alt sınırı olamaz, yani şöyle bir yapı olamaz: sınıf Box<T Harika Sayı> {...} izin verilemez.  Neden?  Cevap şu: anlamsız cizık izinızırın bızılı boyutu ınıbış şey şatız almazı.  Bir tür parametresindeki üst şehrin ne anlama geğlisini közzerek klasıların alt şehir tür parametrerinin neden kafa razgarıcı ığının görelim.

Bir tür parametresindeki üst gehirin ük ektisi vardir:

    1. Kısıtlı Örnekleme. Üst sınır, genel türün başlatılması için kullanılabilecek tür kümesini kısıtlar.  Eğer bir ilan edersek Box<T sınıfı Number>'yi genişletir {...} o zaman derleyici yalnızca alt türlerin olmasını sağlar Sayı tür argümanı olarak kullanılabilir.  Yani, bir Kutu<Numara> veya bir Kutu<Uzun> izin verilir, ancak bir Kutu<Nesne> veya Kutu<String> reddedilecekti

Örnek (bir tür parametresindeki üst sınır nedeniyle kısıtlı örnekleme):
Box<T sınıfı Number>'yi genişletir { 
   özel T değeri; 
   genel Kutu(T t) { değer = t; } 
   ...
}  sınıf Testi { 
   public static void main(String[] args) { 
       Box<Long> boxOfLong = yeni Box<Long>(0L);   // iyi
       Box<String> boxOfString = new Box<String>(""); // hata: String sınırlar dahilinde değil
   }
}

  1. Statik Olmayan Üyelere Erişim. Üst sınır, üst sınırın tüm genel statik olmayan yöntemlerine ve alanlarına erişim sağlar.  Uygulamamızın uygulanmasında Box<T sınıfı Number>'yi genişletir {...} sınıfta tanımlanan tüm genel statik olmayan yöntemleri çağırabiliriz Sayı , örneğin intValue() örneğin.  Üst sınır olmadan derleyici böyle bir çağrıyı reddeder. Örnek (bir tür parametresindeki üst sınır nedeniyle statik olmayan üyelere erişim):

Box<T sınıfı Number>'yi genişletir { 
   özel T değeri; 
   genel Kutu(T t) { değer = t; } 
   public int artırım() { return value.intValue()+1; } // <= Sayı sınırı olmadan bir hata olur
   ...
} 

    1. Silme yazın. En soldaki üst sınır, türün silinmesi için kullanılır ve bayt kodundaki type parametresinin yerine geçer.  bizim Box<T sınıfı Number>'yi genişletir {...} tüm oluşumları T üst sınırla değiştirilecek Sayı .  Örneğin, eğer sınıf Kutu özel bir tür alanına sahiptir T ve bir yöntem geçersiz küme (T içeriği) bu özel alanı ayarlamak için alan şu türden olacaktır: Sayı tip silindikten sonra yöntem bir yönteme çevrilecektir geçersiz küme (Sayı içeriği) .

Örnek (tür silme türünde bir tür parametresinde üst gührın yapılandırması – önce tip silme):
sınıf Box< T Sayıyı genişletir > { 
   özel T değer; 
   genel kutu( T t) { değer = t; } 
   ...
} 

      Örnek (tür silme türünde bir tür parametresinde üst gührın yapılandırması –

sonrasında

      tip silme):

 

sınıf Kutu { 
   özel Sayı değer; 
   genel kutu( Sayı t) { değer = t; } 
   ...
}

    Ek olarak, en soldaki üst sınır, otomatik olarak eklenen dönüşümler ve köprü yöntemleri gibi başka konumlarda da görünür.

Tip parametrelerinde alt sınırlara izin verilseydi, bunların hangi yan etkileri olurdu veya olması gerekirdi? Eğer böyle bir yapı varsa sınıf Box<T Harika Sayı> {...} izin verdiyse bu ne anlama gelir?  Üst uç parametre kırının – sınırlı örnek, statik statik olmayan kullanıcı erişimi, tür silme – 3 yan etkisi bir alt kırın için ne anlama gelir?

Kısıtlanmış Örnekler. Derleyici, genel türün başlatılması için kullanılabilecek tür kümesini bir alt sınır tür parametresiyle kısıtlayabilir.  Örneğin, derleyici aşağıdaki gibi örneklemelere izin verebilir: Kutu<Numara> Ve Kutu<Nesne> birinden Kutu<T Harika Numara> ve gibi örneklemeleri reddedin Kutu<Uzun> veya Kutu<Kısa> .  Bu, üst tip parametre sınırları için açıklanan kısıtlayıcı yan etki doğrultusunda bir etki olacaktır.

Statik Olmayan Üyelere Erişim. Daha düşük türde bir parametre sınırı, sınıftan miras alınanların ötesinde herhangi bir belirli yönteme erişim sağlamaz Nesne . Örneğinde Kutu<T Harika Numara> süper türleri Sayı Referans türleri ve dolayısıyla alt türleri olmaları dışında ortak hiçbir yanı yoktur. Nesne .  Derleyici, tür alanının olduğunu varsayamaz. T türden Sayı veya bunun bir alt türü.  Bunun yerine, yazı alanı T herhangi bir süper tipte olabilir Sayı , örneğin Serileştirilebilir veya Nesne .  Gibi bir yöntemin çağrılması intValue() artık tür açısından güvenli değil ve derleyicinin bunu reddetmesi gerekecek. Sonuç olarak, alt tür parametre sınırı, sınıfta tanımlananların ötesinde statik olmayan üyelere erişim vermez. Nesne ve hindite “sınır yok” ile aynı etkiye sahiptir.

Türü Silme .  Bu mantık çizgisini takip ederek, type parametresinin oluşumlarını en soldaki alt sınırla değiştirmek mantıklı değildir.  Yapıcı gibi bir yöntem bildirmek Kutu( T T) yapıcı olarak Kutu( Sayı T) bunu göz önünde bulundurursak mantıklı değil T bir süper tip ile değiştirilir Sayı .  Bir Nesne bir örnekte yapıcıya doğru bir şekilde aktarılabilir Kutu<Nesne> ve yapıcı bunu reddeder.  Bu tamamen yanlış olurdu.   Dolayısıyla, tür silme, tür değişkeninin tüm oluşumlarının yerini alacaktır T türe göre Nesne ve alt gehirine göre değil.  Yine de alt führer “sınır yok” ile aynı etkiyi yarattık.

Onun ikis de daha gyögö olssa bunun ne anlamanı kalıcı olarak ister misin? _Ve_ üst führlara izin verdi mi?   Şahsen ben bunu diminek bile ışığım ve izin verilirse “yönetilemez” kategorisine käptemayi teşir ederim.

Sonuç olarak: tüm alıcı bir “ Harika ” seni tätsın almak için bindı olmak ışığırın süper tiplerin geüleri tılı bir sırtımındır Sayı tür argümanları olarak kullanılabilir.  Ve bu bile sıklıkla yanlış anlaşılıyor.  Bu şu anlama gelmez sınıf Box<T süper Sayı> {...} yalnızca süper tiplerin örneklerini içerir Sayı .  Tam tersi; gördüğünüz şeyin aşağıdaki örneği!

Örnek (tür silme türünde bir tür parametresinde üst gührın yapılandırması – önce tip silme):

sınıf Box< T süper numarası > {
   özel T değer;
   genel kutu( T t) { değer = t; }
   ...
}

Örnek (tür silme türünde bir tür parametresinde üst gührın yapılandırması – sonrasında tip silme):

sınıf Kutu {
   özel Nesne değer;
   genel kutu( Nesne t) { değer = t; }
   ...
}

A sınıf Box<T Harika Sayı> {...} tür silme işlemine göre bir dile çevrilecektir Kutu içeren Nesne alanı ve yapıcısı şuraya çevrilecektir: Kutu(Nesne t) . Bu temelde farklı bir sınıf Box<T uzanır Sayı> {...} , şu dile çevrilecek: Kutu içeren Sayı alanı ve yapıcısı şuraya çevrilecektir: Kutu(Sayı t) . Sonuç olarak, bir Kutu<Numara> bir örnekten başlatıldı Box<T sınıfı Number>'yi genişletir {...} birinden farklı olurdu Kutu<Numara> bir örnekten örnekleme sınıf Box<T süper Sayı> {...} kızıllığı yol açması problemimdir.  Bu nedenle uç parametrelerinde sınıfların bir anlamı yoktur.

 


 

Yöntemlerin Alt Sınır Türü Parametreleri

Yöntemler ve indunin bağımsız değişken türleri ile yıldız, alt ışık saatib bir tür parametresi bazen sizilı ınılız.

Örnek:

sınıf Çift<X,Y> {
   önce özel X;
   özel Y saniye;
   ...
   halka açık < Süper bir X , B süper Y > B addToMap(Map<A,B> haritası) { // hata: tür parametresinin alt sınırı olamaz
      return map.put(birinci, ikinci);
   }
}
sınıf Testi { 
   public static void main(String[] args) { 
     Pair<String,Long> çifti = yeni Pair<>("ABC",42L);
     Map<CharSequence, Number> haritası = HashMap<CharSequence, Number>();
     Sayı numarası = çift.addToMap(harita);
   }
}

Bu addToMap() yöntemi çiftin içeriğini bir haritaya ekler.  Süper türlerini tutabilen herhangi bir harita X Ve e yapardı.  Haritanın koymak() yöntem, haritada anahtar için zaten bir anahtar/değer girişi varsa, verilen anahtar için haritada bulunan değeri döndürür.  Haritanın dönüş değeri koymak() yöntem iade edilecektir. addToMap() Yöntem.  Bu koşullar altında, yukarıda gösterilen yöntemi bildirmek isteriz: Harita, çiftin tür parametrelerinin üst türleriyle parametrelendirilir ve addToMap() tür türü haritasının ve tür türü dür

Derleyici tür parametrelinde alt geirlara izin vermekten, tähälä bir sözüse türümüğü var.

Akla gelen tähälä tälääden biri joker karakter kullanmaktır çünkü joker karakterlerinin bir alt ışığı öğüri.  Burada geçici bir çözüm kullanarak bir joker karakteri bulabilirsiniz.

Örnek (joker karakterleri kullanan önceki örnek için geçici çözüm):

sınıf Çift<X,Y> {
   önce özel X;
   özel Y saniye;
   ...
   halk Nesne addToMap(Map< ? Süper X , ? süper Y > haritası) { 
      return map.put(birinci, ikinci);
   }
}
sınıf Testi { 
   public static void main(String[] args) { 
     Pair<String,Long> çifti = yeni Pair<>("ABC",42L);
     Map<CharSequence, Number> haritası = HashMap<CharSequence, Number>();
     Numara numarası = (Sayı) çift.addToMap(harita);
   }
}

Dönüş türünü istendiği gibi bildirmenin bir yolu olmaması dışında işe yarar.  Süper tipi olurdu e derleyicinin haritadan yakaladığı, bir söz dizimi yoktur için bunu behirlemek.  Dönüştürülmesini bir olarak bildirmemilys “ ? süper Y “, Çünkü “ ? süper Y ” bir joker karakterdir ve bir tür ındırındır ve bu çıkışın itürü olarak veğlerin kullanılmasına izin verilmez. Başka seçeneğimiz yok ve onu kullanmak zorundayız: Nesne bunun yerine yöntemimizin dönüş türü olarak.  Bu oldukça spesifik olmayan dönüş türü, arayanları zorlar. addToMap() dönüş değerini aşağıya çevirme yöntemi Nesne gerçek tip Aklımızdaki tam olarak bu naydı.

Başka bir türkçe çözülmüş statik metodolındır.  Statik olan bir metsod yirine statik olan bir tähälä tähälä burada ındağırik.

Örnek (statik bir yöntem kullanan önceki örnek için geçici çözüm):

sınıf Çift<X,Y> {
   önce özel X;
   özel Y saniye;
   ...
   halk statik < A , B ,X A'yı genişletir ,Y B'yi uzatır > B addToMap(Pair<X,Y> çifti, Map<) A , B > haritası) {
      return map.put(çift.ilk,çift.ikinci);
   }
}
sınıf Testi { 
   public static void main(String[] args) { 
     Pair<String,Long> çifti = yeni Pair<>("ABC",42L);
     Map<CharSequence, Number> haritası = HashMap<CharSequence, Number>();
     Numara numarası = Çift .addToMap( çift ,harita);
   }
}

jenerik addToMap() yöntemin dört tür parametresi vardır: iki yer tutucu X Ve e çiftin türü ve iki yer tutucu için A Ve B Haritanın türü için. A Ve B süper türleridir X Ve e , Çünkü X Ve e   ile beyan edilir A Ve B üst sınırları olarak. (Genel yöntemin tür parametrelerinin X Ve e konuyla hiçbir ilgisi yok Çift sınıfın X Ve e parametreler.  İsimler X Ve e çiftin tür parametreleri olarak fazılı tanınabilmelerini sağımık inte genel mesztılı için yeniden bağlanır. Dört tip parametresi kesin kursun tipini sılımız gibi bildirızılızın kesin kurşın tipini gibi bildiririzın: haritanın denğar tipiyle şinin tipidir.

Örnek (genel bir sınıfın statik baglamında tip parametrelerinin yasa dışı kullanımı Rışının):

sınıf Bazı Sınıf <T> {
  // statik başlatıcı, statik alan, statik yöntem
  statik {
    Bazı Sınıflar< T > testi = yeni SomeClass< T >(); // hata
  }
  özel statik T küreselBilgi;          // hata
  halk  statik T getGlobalInfo() {        // hata
    globalInfo'yu döndür;
  }
  // statik olmayan başlatıcı, statik olmayan alan, statik olmayan yöntem
  { 
    Bazı Sınıflar< T > testi = yeni SomeClass< T >();
  }
  özel        T yerelBilgi;
  halk         T getLocalInfo() { 
    localInfo'yu döndür;
  }
  // Statik iç içe geçmiş türler
  halk statik sınıf Başarısızlık İstisnayı genişletir {
    özel final T bilgi;           // hata
    genel başarısızlık( T t) { bilgi = t; }      // hata
    halk T getInfo() { bilgi döndür; }    // hata
   }
  özel arayüz Kopyalanabilir {
    T kopyala();                       // hata
  }
  özel numaralandırma Durum {
    GEÇERLİ, GEÇERSİZ;
    özel T bilgi; // hata
    genel geçersiz setInfo( T t) { bilgi = t; } // hata
    halk T getInfo() { bilgi döndür; }    // hata
  }
  // statik olmayan iç içe geçmiş türler
  halk sınıf Erişimci {
    halk T getInfo() { localInfo'yu döndür; }
  }
}

Örnekte tip parametresinin genel bir klassin statik özelliklerinin kullanılamadığı gösterilmiştir.  Ayrıca, iç içe tarifelerin ve numaralandırma türünün klasın statik türler olarak kabul diğırını belirtiyorlar.  Sadece iç klasslar yani statik olmayan iç içe geçmiş klasslar, çevreleyen genel klassin tipi parametrelerini kullanabilir.

Bir araririmin tür parametresinin issembe, alanlar veya iç içe goçem türler araşa arayüzüin tüm tanımıdır.  Bunun neendi, bir gelişimde ışığınan alanin ve iç içe goçem tegurin tervülü olarak statik indığın.

Örnek:

arayüz SomeInterface <T> {
  // alan
  Bazı Sınıflar< T > değeri = yeni SomeClass< T >();  // hata
  // iç içe geçmiş tür
  sınıf Erişimci {
    halk T getInfo() {            // hata
      dönüş değeri.getGlobalInfo();
    }
  }
  // yöntemler
  T getValue();
}

Örnek, bir arabirimin alanlarının dolaylı olarak statik olduğunu, dolayısıyla type parametresinin genel bir arabirimin alan bildiriminin herhangi bir yerinde kullanılamayacağını gösterir.  Benzer şekilde, iç içe geçmiş sınıf, bir iç sınıf değil, statik iç içe geçmiş bir sınıf olarak kabul edilir ve bu nedenle, iç içe geçmiş sınıfın herhangi bir yerinde type parametresinin kullanılması yasa dışıdır.

İç içe geçmiş statik sınıflar ve arayüzler için geçici çözüm:

Statik iç sınıflar ve dağıtımlar söz konusu içinde bu büyük bir felaket dırındadır.  Geçici bir çözüm olarak statik sınıf veya arayüz seçimiyle geçinebilirsiniz.

Örnek:

sınıf Paketleyici <T> {
  özel final T Nesne;

  genel Paketleyici( T t) { Nesne = t; }
  halk T getWrapper() { Nesneyi döndürür; }   halka açık Değişmez <T> makeImmutable() {
        yeni Değişmezi döndür <T> (Nesne);
  }
  herkese açık Değişken <T> makeMutable() {
        yeni Mutable'ı döndür <T> (Nesne);
  }
  özel statik <A> A makeClone(A theObject) { ... }

  public statik son sınıf Değişmez <A> { // artık genel bir sınıf
        özel final A Nesne;

        genel Değişmez( A argüman) {
            theObject = makeClone(arg);
        }
        halk A getWrappedItem() {
            makeClone(theObject) işlevini döndürün;
        }
  }
  genel statik sınıf Değiştirilebilir <A> {
        ... benzer ...
  }
}

Genel olamayacakları için iç içe numaralandırma türleri için böyle bir geçici çözüm yoktur.

İç içe geçmiş statik sınıflar için geçici çözüm:

İç içe geçme statik tür bir klasik alternatifin bir tähliy çözülmüş, statik klasik statik olan bir iç klasik kazılımak olur.

Örnek (geçici çözüm – bir iç klassık kaylin):

sınıf Paketleyici <T> {
  özel final T Nesne;

  genel Paketleyici( T t) { Nesne = t; }
  halk T getWrapper() { Nesneyi döndürür; }   public Değişken makeMutable() {
      geri dönmek Bu. new Mutable(theObject);
  }
  public Değişmez makeImmutable() {
      geri dönmek Bu. new Değişmez(theObject);
  }
  özel statik <A> A makeClone(A theObject) { ... }

  genel son sınıf Değişmez {  // artık statik bir sınıf değil
      özel final T Nesne;

      genel Değişmez( T argüman) {
          theObject = makeClone(arg);
      }
      halk T getWrappedItem() {
          makeClone(theObject) işlevini döndürün;
      }
  }
  genel sınıf Değiştirilebilir 
        ... benzer ...
  }
}

Bu türköy çözü bir suüzütü ek yükti berebirinde getirici tüm iç klassıların düş tyürun bir sashine gizli bir referansı vardır; bu şışkte buna ne şişik duyarlar ne de bundan ışıklar; gizli referanslar beseket bagagdır.  Çok zaman, iç klassları kireileyen klassin özel bir uylikama detayı olarak tutmak için iç klasslar tarifelerle komstabilir.  Burada da tezinisini kızlarız.

Örnek:

sınıf Paketleyici <T> {
  özel final T Nesne;

  genel Paketleyici( T t) { Nesne = t; }
  halk T getWrapper() { Nesneyi döndürür; }   herkese açık Değişken <T> makeMutable() {
      return this.new Mutable(theObject);
  }
  halka açık Değişmez <T> makeImmutable() {
      return this.new Immutable(theObject);
  }
  özel statik <A> A makeClone(A theObject) { ... }

  genel arayüz Değiştirilemez<S> {
      S getWrappedItem();
  }
  genel arayüz Değiştirilebilir<S> {
      S getWrappedItem();
      void setWrappedItem(S arg);
  }
  özel son sınıf Değişmez Uygulama Değişmez<T>'yi uygular { 

      özel final T theObject;

      public ImmutableImplementation(T arg) {
          theObject = makeClone(arg);
      }
      genel T getWrappedItem() {
          makeClone(theObject) işlevini döndürün;
      }
  }
  özel sınıf MutableImplementation Mutable<T>'yi uygular { 
        ... benzer ...
  }
}

Gördüküniz gibi, iç içe goçem genel dağıtımların genel olsisi geğlirken iç özel klassılar, kireileyen klassin tipi parametresini kullarıber.

 

 

 

 

 

Bir Yanıt Bırakın

Velislav Krastev Blog'dan daha fazlasını keşfedin

Okumaya devam etmek ve arşivin tamamına erişmek için şimdi abone olun.

Okumaya devam et