Joker karakter (Java) - Wildcard (Java)

Joker ? içinde Java tip argüman özel bir türüdür kontrol ettiği kullanımının tip emniyet jenerik (parametreli) türleri. Değişken bildirimlerinde ve somutlaştırmalarında olduğu kadar yöntem tanımlarında da kullanılabilir, ancak genel bir türün tanımında kullanılamaz. Bu, C # ve Scala'da bulunan tanım sitesi varyans ek açıklamalarının aksine, kullanım alanı varyans ek açıklamasının bir biçimidir .

Genel türler için kovaryans

(Vardır aksine diziler eşdeğişkin Java), genel bir tür farklı örneklemi bile açıkça, birbiriyle uyumlu değil: beyanı ile Generic<Supertype> superGeneric; Generic<Subtype> subGeneric; derleyici hem dökümler için bir dönüştürme hatası rapor verecek (Generic<Subtype>)superGeneric ve (Generic<Supertype>)subGeneric .

Bu uyumsuzluk, ? gerçek bir tür parametresi olarak kullanılıyorsa joker karakterle yumuşatılabilir : Generic<?> genel türdeki tüm parametre ayarlamalarının bir süper tipidir Generic . Bu tür nesneler sağlar Generic<Supertype> ve Generic<Subtype> güvenli bir şekilde tipte bir değişken ya da yöntem parametresi tayin edilmesi Generic<?> . Kullanımı Generic<? extends Supertype> aynı şeyi sağlar, uyumluluğu kısıtlar Supertype ve çocukları. Diğer bir olasılık, Generic<? super Subtype> hem nesneleri kabul eden hem de uyumluluğu Subtype ve tüm ebeveynleri ile kısıtlayan olmasıdır .

Parametre türü olarak joker karakter

Genel birimi gövdesinde, (kayıtlı) tür parametresi onun gibi işlenir üst sınırı (ifade extends ; Object kısıtlı değilse). Bir yöntemin dönüş türü tür parametresiyse, sonuca (örneğin tür ? ), üst sınırın (veya Object ) türünün bir değişkeni tarafından başvurulabilir . Diğer yönde, joker karakter başka hiçbir türe uymaz, hatta Object : ? Bir yöntemin biçimsel tür parametresi olarak uygulanmışsa, ona hiçbir gerçek parametre geçirilemez. Bununla birlikte, bilinmeyen türdeki nesneler, genel nesneden okunabilir ve üst sınırın bir üst türünün bir değişkenine atanabilir.

class Generic <T extends UpperBound> {
    private T t;
    void write(T t) {
        this.t = t;
    }
    T read() {
        return t;
    }
}
...
Generic<UpperBound> concreteTypeReference = new Generic<UpperBound>();
Generic<?> wildcardReference = concreteTypeReference;
UpperBound ub = wildcardReference.read(); // Object would also be OK
wildcardReference.write(new Object()); // type error
wildcardReference.write(new UpperBound()); // type error
concreteTypeReference.write(new UpperBound()); // OK

Sınırlı joker karakterler

Sınırlı bir joker karakter, üst veya alt kalıtım sınırlamasına sahip olandır. Bir joker karakterin sınırı, bir sınıf türü, arabirim türü, dizi türü veya tür değişkeni olabilir. Üst sınırlar extends anahtar sözcüğü ve alt sınırlar süper anahtar sözcüğü kullanılarak ifade edilir . Joker karakterler bir üst sınır veya bir alt sınır belirtebilir , ancak her ikisini birden belirtemez.

Üst sınırlar

Bir joker karakter üzerindeki üst sınır, karşılık gelen genel türde bildirilen karşılık gelen tür parametresinin üst sınırının bir alt türü olmalıdır. Bir üst sınırı açıkça belirten bir joker karakter örneği şöyledir:

Generic<? extends SubtypeOfUpperBound> referenceConstrainedFromAbove;

Bu başvuru Generic , tür bağımsız değişkeninin alt türü olan herhangi bir parametreleştirmeyi tutabilir SubtypeOfUpperBound . Bir üst sınırı açıkça belirtmeyen bir joker karakter, extends Object Java'daki tüm başvuru türleri Object'in alt türleri olduğundan , kısıtlamaya sahip olanla etkin bir şekilde aynıdır .

Alt sınırlar

Alt sınırı olan bir joker karakter, örneğin

Generic<? super SubtypeOfUpperBound> referenceConstrainedFromBelow;

herhangi Generic bir tür bağımsız değişkeni hem karşılık gelen tür parametresinin üst sınırının bir alt türü hem de bir üst türü olan herhangi bir parametreleştirmeyi tutabilir SubtypeOfUpperBound .

Joker karakterle nesne oluşturma

Joker karakter türü bağımsız değişkenle hiçbir nesne oluşturulamaz: örneğin new Generic<?>() yasaktır. Pratikte bu gereksizdir, çünkü eğer biri bir tür değişkenine atanabilir bir nesne yaratmak istendiğinde Generic<?> , herhangi bir keyfi türü (varsa joker karakterin kısıtlamaları dahilinde olan) tür bağımsız değişkeni olarak kullanabilir.

Bununla birlikte, new ArrayList<Generic<?>>() joker karakter başlatılan türün bir parametresi olmadığı için izin verilir ArrayList . Aynısı için de geçerlidir new ArrayList<List<?>>() .

Bir dizi oluşturma ifadesinde, dizinin bileşen türü, Java Dil Spesifikasyonu, Bölüm 4.7'de tanımlandığı gibi yeniden değiştirilebilir olmalıdır. Bu, dizinin bileşen türünde herhangi bir tür bağımsız değişkeni varsa, bunların hepsinin sınırsız joker karakterler olması gerektiğini (yalnızca a'dan oluşan joker karakterler ? ) gerektirir. Örneğin new Generic<?>[20] , doğru, süre new Generic<SomeType>[20] değil.

Her iki durumda da parametre kullanmamak başka bir seçenektir. Bu, tür açısından daha az güvenli olduğundan bir uyarı oluşturacaktır (bkz. Ham tür ).

Örnek: Listeler

Java Collections Framework'te, sınıf List<MyClass> , türdeki nesnelerin sıralı bir koleksiyonunu temsil eder MyClass . Üst sınırlar şu şekilde belirtilir extends : A List<? extends MyClass> , bazı alt sınıfların nesnelerinin bir listesidir MyClass , yani listedeki herhangi bir nesnenin türünde olması garanti edilir MyClass , böylece bir tür değişkeni kullanılarak üzerinde yineleme yapılabilir. MyClass

public void doSomething(List<? extends MyClass> list) {
    for (MyClass object : list) { // OK
        // do something
    }
}

Ancak, bu MyClass listeye herhangi bir türden nesnenin eklenebileceği garanti edilmez :

public void doSomething(List<? extends MyClass> list) {
    MyClass m = new MyClass();
    list.add(m); // Compile error
}

Tersi, aşağıdakiler kullanılarak belirtilen alt sınırlar için doğrudur super : A List<? super MyClass> , bir üst sınıfın nesnelerinin bir listesidir MyClass , yani listenin herhangi bir türde nesneyi içerebilmesi garanti edilir MyClass , böylece herhangi bir tür nesne eklenebilir MyClass :

public void doSomething(List<? super MyClass> list) {
    MyClass m = new MyClass();
    list.add(m); // OK
}

Bununla birlikte, bir tür değişkeni kullanarak bu listenin üzerinde yineleme yapılabileceği garanti edilmez MyClass :

public void doSomething(List<? super MyClass> list) {
    for (MyClass object : list) { // Compile error
        // do something
    }
}

Amacıyla tip her iki eklenti nesneleri yapabilmek için MyClass yinelerler türünde bir değişken kullanarak bitti listeye ve MyClass bir List<MyClass> tek türü olan ihtiyaç List olduğunu hem de List<? extends MyClass> ve List<? super MyClass> .

Kitaptan kısaltmalar PECS (Yapımcı, Tüketici Süper Uzattı) Etkili Java tarafından Joshua Bloch Java (Kovaryans ve contravariance karşılık gelir) joker kullanmak hatırlamak için kolay bir yol sağlar.

Ayrıca bakınız

Referanslar