Ham tip nedir ve neden kullanmamalıyız?


662

Sorular:

  • Java'da ham türler nelerdir ve neden yeni kodlarda kullanılmamaları gerektiğini sık sık duyuyorum?
  • Ham türleri kullanamıyorsak alternatif nedir ve nasıl daha iyidir?

java eğiticileri hala bu uyarıya neden olan JComboBox kullanmaktadır. Açılan kutunun hangi sürümü bu uyarıya neden olmaz? docs.oracle.com/javase/tutorial/uiswing/components/…
SuperStar

1
Ham türlerin var olmasının nedeninin, hiç jenerik içermeyen Java 1.4 ve daha eski sürümlerle geriye dönük uyumluluk olduğunu unutmayın.
Jesper

Yanıtlar:


744

Ham tip nedir?

Java Dil Belirtimi ham türü aşağıdaki gibi tanımlar :

JLS 4.8 Ham Çeşitleri

Ham tür aşağıdakilerden biri olarak tanımlanır:

  • Eşlik eden tür bağımsız değişken listesi olmadan genel tür bildirimi adı alınarak oluşturulan başvuru türü.

  • Öğe türü ham tür olan bir dizi türü.

  • Öğesinin üst sınıfından veya üst yüzeyinden miras alınmayan staticüye olmayan bir ham tür .RR

Aşağıda açıklamak için bir örnek verilmiştir:

public class MyType<E> {
    class Inner { }
    static class Nested { }

    public static void main(String[] args) {
        MyType mt;          // warning: MyType is a raw type
        MyType.Inner inn;   // warning: MyType.Inner is a raw type

        MyType.Nested nest; // no warning: not parameterized type
        MyType<Object> mt1; // no warning: type parameter given
        MyType<?> mt2;      // no warning: type parameter given (wildcard OK!)
    }
}

Burada, MyType<E>bir olduğunu parametreli tip ( JLS 4.5 ). Halk dilinde bu tipe kısaca kısaca değinmek yaygındır MyType, ancak teknik olarak isimdir MyType<E>.

mtyukarıdaki tanımdaki ilk madde işareti noktasına göre ham bir türe sahiptir (ve bir derleme uyarısı üretir); innayrıca üçüncü mermi noktasına göre ham bir türe sahiptir.

MyType.Nestedparametreli bir türün üye türü olmasına rağmen parametreli bir tür değildir MyType<E>, çünkü static.

mt1, ve mt2her ikisi de gerçek tür parametreleriyle bildirildiğinden, bunlar ham tür değil.


Ham türlerde bu kadar özel olan ne?

Temel olarak, ham türler tıpkı jenerik ilaç kullanılmadan önceki gibi davranır. Yani, derleme zamanında aşağıdakiler tamamen yasaldır.

List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!

Yukarıdaki kod gayet iyi çalışıyor, ancak aşağıdakilere de sahip olduğunuzu varsayalım:

for (Object o : names) {
    String name = (String) o;
    System.out.println(name);
} // throws ClassCastException!
  //    java.lang.Boolean cannot be cast to java.lang.String

Şimdi çalışma zamanında sorun yaşıyoruz, çünkü namesolmayan bir şey içeriyor instanceof String.

İstersen Tahminen, namessadece içerdiği String, sen olabilir belki hala ham türü kullanmak ve her kontrol elle add kendinizi ve sonra elle dökme için Stringher öğenin names. Daha da iyisi , ham bir tür kullanmak DEĞİLDİR ve derleyicinin sizin için tüm işleri yapmasına izin vermek, Java jeneriklerinin gücünü kullanmaktadır.

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

Eğer değilse, doğal DO istediğiniz namesbir izin Boolean, o zaman olarak ilan edebilir List<Object> namesve yukarıdaki kod derlemek olacaktır.

Ayrıca bakınız


Ham türün <Object>tür parametresi olarak kullanılmasından farkı nedir?

Effective Java 2nd Edition, Item 23'ten bir alıntı : Yeni kodda ham türleri kullanmayın :

Ham tip Listve parametreli tip arasındaki fark List<Object>nedir? Gevşek bir şekilde, birincisi genel tip kontrolünü devre dışı bırakırken, ikincisi derleyiciye herhangi bir türdeki nesneyi tutabildiğini açıkça söyledi. A List<String>türünde Listbir parametreye geçebilse de, türdeki bir parametreye iletemezsiniz List<Object>. Jenerikler için alt tipleme kuralları vardır List<String>ve ham tipin bir alt tipidir List, ancak parametrelenmiş tipte değildir List<Object>. Sonuç olarak, gibi ham tür kullanırsanız tür güvenliğini kaybedersiniz List, ancak gibi parametreli bir tür kullanırsanız tür güvenliğini kaybedersinizList<Object> .

Noktayı göstermek için, a alan List<Object>ve a ekleyen aşağıdaki yöntemi göz önünde bulundurun new Object().

void appendNewObject(List<Object> list) {
   list.add(new Object());
}

Java'daki jenerikler değişmezdir. A List<String>bir değildir List<Object>, bu nedenle aşağıdakiler derleyici uyarısı oluşturur:

List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!

appendNewObjectHam türü Listparametre olarak almayı bildirdiyseniz , bu derlenir ve bu nedenle jeneriklerden aldığınız tür güvenliğini kaybedersiniz.

Ayrıca bakınız


Ham türün <?>tür parametresi olarak kullanılmasından farkı nedir?

List<Object>,, List<String>vs. hepsi List<?>, bu yüzden sadece Listbunun yerine olduklarını söylemek cazip gelebilir . Bununla birlikte, büyük bir fark vardır: List<E>sadece bir tanımladığından add(E), a'ya herhangi bir keyfi nesne ekleyemezsiniz List<?>. Öte yandan, ham tipin Listtip güvenliği olmadığından, addhemen hemen her şeyi yapabilirsiniz List.

Önceki snippet'in aşağıdaki varyasyonunu düşünün:

static void appendNewObject(List<?> list) {
    list.add(new Object()); // compilation error!
}
//...

List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!

Derleyici, sizi potansiyel tipinin değişmezliğini ihlal etmekten korumak için harika bir iş çıkardı List<?>! Parametreyi ham tür olarak bildirdiyseniz, List listkod derlenir ve tür değişmezini ihlal ederdiniz List<String> names.


Ham tür, bu türün silinmesidir

JLS 4.8'e geri dön:

Bir tür olarak kullanmak mümkündür silinmesini parametreli bir türü ya da eleman türü parametreli bir türü olan bir dizi türü sılme. Böyle bir türe ham tip denir .

[...]

Ham tipin üst sınıfları (sırasıyla üst sınıflar), genel tipteki parametrelerin herhangi birinin üst sınıflarının (üst sınıfları) silinmeleridir.

Üst sınıflarından veya üst sınıflarından miras alınmayan staticbir ham türün yapıcısı, örnek yöntemi veya alan dışı Ctürü, karşılık gelen genel bildirimde türünün silinmesine karşılık gelen ham türdür C.

Daha basit bir çiğ türü kullanılıyor terimler, yapıcılar, örnek yöntemlerde ve sivil olarak staticalanlar vardır da silinir .

Aşağıdaki örneği alın:

class MyType<E> {
    List<String> getNames() {
        return Arrays.asList("John", "Mary");
    }

    public static void main(String[] args) {
        MyType rawType = new MyType();
        // unchecked warning!
        // required: List<String> found: List
        List<String> names = rawType.getNames();
        // compilation error!
        // incompatible types: Object cannot be converted to String
        for (String str : rawType.getNames())
            System.out.print(str);
    }
}

Biz çiğ kullandığınızda MyType, getNamesbir ham döndüren böylece, sıra silinir olur List!

JLS 4.6 aşağıdakileri açıklamaya devam eder:

Tür silme ayrıca bir kurucu veya yöntemin imzasını, parametrelenmiş tür veya tür değişkeni olmayan bir imzayla eşler. Bir kurucunun veya yöntem imzasının silinmesi s, aynı ad sve verilen tüm resmi parametre türlerinin silinmesinden oluşan bir imzadır s.

Bir yöntemin dönüş türü ve genel bir yöntemin veya kurucunun tür parametreleri de, yöntemin veya kurucunun imzası silinirse silinir.

Genel bir yöntemin imzasının silinmesinin hiçbir tür parametresi yoktur.

Aşağıdaki hata raporu, derleyici geliştirici Maurizio Cimadamore ve JLS'nin yazarlarından Alex Buckley'den bu tür davranışların neden ortaya çıkması gerektiğine dair bazı düşünceler içeriyor: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Kısacası, spesifikasyonu kolaylaştırır.)


Güvenli değilse, neden ham tür kullanılmasına izin verilir?

İşte JLS 4.8'den başka bir alıntı:

Ham türlerin kullanımına yalnızca eski kodun uyumluluğundan taviz olarak izin verilir. Java programlama diline jenerikliğin girilmesinden sonra yazılan kodda ham türlerin kullanılması kesinlikle önerilmez. Java programlama dilinin gelecekteki sürümlerinin ham türlerin kullanımına izin vermemesi mümkündür.

Etkili Java 2nd Edition ayrıca şunları eklemek için:

Ham türleri kullanmamanız gerektiği göz önüne alındığında, dil tasarımcıları neden onlara izin verdi? Uyumluluk sağlamak.

Java platformu, jenerikler tanıtıldığında ikinci on yılına girmek üzereydi ve jenerikler kullanmayan muazzam miktarda Java kodu vardı. Tüm bu kodların yasal ve jenerik ilaç kullanan yeni kodlarla birlikte çalışabilir olması kritik kabul edildi. Parametreli türlerin örneklerini sıradan türlerle kullanılmak üzere tasarlanmış yöntemlere geçirmek yasal olmalıdır (tersi de geçerlidir). Göç uyumluluğu olarak bilinen bu gereklilik, ham türleri destekleme kararını vermiştir.

Özetle, ham tipler ASLA yeni kodda kullanılmamalıdır. Her zaman parametreli tipler kullanmalısınız .


İstisna yok mu?

Ne yazık ki, Java jenerikleri birleştirilmediğinden, ham türlerin yeni kodda kullanılması gereken iki istisna vardır:

  • Sınıf sabitler, örneğin List.class, değilList<String>.class
  • instanceofoperand, örneğin o instanceof Set, değilo instanceof Set<String>

Ayrıca bakınız


16
"Java jenerikleri birleştirilmiyor" demekle ne demek istiyorsun?
Carl G

7
İkinci istisna için, sözdiziminin o instanceof Set<?>ham türden kaçınmasına da izin verilir (ancak bu durumda sadece yüzeyseldir).
Paul Bellora

1
Ham türler çok yararlıdır ve bir arabirimi genişleten bir fasulye için JNDI aramaları durumunda kazan plakasını azaltır. Bu n, her bir uygulama sınıfı için aynı kodla uzak fasulye yazma ihtiyacını çözer .
djmj

8
"Reified olmayan", silindiklerini söylemenin başka bir yoludur. Derleyici, genel parametrelerin ne olduğunu bilir, ancak bu bilgiler oluşturulan bayt koduna aktarılmaz. JLS, sınıf değişmezlerinin hiçbir tür parametresine sahip olmamasını gerektirir.
Erick G. Hagstrom

2
@OldCurmudgeon Bu ilginç. Yani resmi olarak da öyle değil , çünkü sadece tanımlanmış bir sınıf değişmezi TypeName.class, TypeNamedüz bir tanımlayıcı ( jls ). Varsayımsal olarak konuşmak gerekirse, sanırım gerçekten de olabilir. Belki bir ipucu olarak, List<String>.classJLS'nin özellikle bir derleyici hatası çağırdığı varyanttır, bu yüzden dilin içine eklerse, kullandıkları tek şey olmasını beklerdim.
Radiodef

62

Java'da ham türler nelerdir ve neden yeni kodlarda kullanılmamaları gerektiğini sık sık duyuyorum?

Ham türler Java dilinin eski tarihidir. Başlangıçta vardı Collectionsve onlar düzenlenen Objectshiçbir şey daha az şey. İstenen tipe Collectionskadar her işlem Objectistenilen tipte.

List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);

Bu çoğu zaman işe yararken, hatalar meydana geldi

List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here

Eski daktilo koleksiyonları tip güvenliğini zorlayamadı, bu yüzden programcı bir koleksiyon içinde ne sakladığını hatırlamak zorunda kaldı.
Bu sınırlamanın üstesinden gelmek için icat edilen jenerikler, geliştirici depolanan türü bir kez beyan eder ve derleyici bunu yapar.

List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine

Karşılaştırma için:

// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings

Karşılaştırılabilir arayüz daha karmaşık:

//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
   int id;
   public int compareTo(Object other)
   {return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
   int id;
   public int compareTo(MyCompareAble other)
   {return this.id - other.id;}
}

CompareAbleArabirimin compareTo(MyCompareAble)ham türlerle uygulanmasının imkansız olduğunu unutmayın . Bunları neden kullanmamalısınız:

  • A'da Objectsaklananlar Collectionkullanılmadan önce dökülmelidir
  • Jenerik kullanımı derleme zaman kontrolleri sağlar
  • Ham türleri kullanmak, her bir değeri depolamakla aynıdır Object

Derleyici ne yapar: Generics geriye dönük olarak uyumludur, ham türlerle aynı java sınıflarını kullanırlar. Sihir çoğunlukla derleme zamanında gerçekleşir.

List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);

Aşağıdaki gibi derlenecektir:

List someStrings = new ArrayList();
someStrings.add("one"); 
String one = (String)someStrings.get(0);

Bu, ham türleri doğrudan kullandıysanız yazacağınız kodla aynıdır. CompareAbleArayüzde ne olacağından emin değilim , sanırım iki compareToişlev yaratıyor , biri a MyCompareAbleve diğeri bir alıyor Objectve onu yayınladıktan sonra ilkine geçiriyor.

Ham türlere alternatifler nelerdir: Jenerik kullanımı


30

Ham tür, herhangi bir tür bağımsız değişkeni olmayan genel bir sınıfın veya arabirimin adıdır. Örneğin, genel Box sınıfı göz önüne alındığında:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Parametreli bir tür oluşturmak Box<T>için, formal type parametresi için gerçek bir tür bağımsız değişkeni sağlarsınız T:

Box<Integer> intBox = new Box<>();

Gerçek tür bağımsız değişkeni atlanırsa, ham türden bir tür oluşturursunuz Box<T>:

Box rawBox = new Box();

Bu nedenle, Boxgenel tipin ham türüdür Box<T>. Ancak, genel olmayan bir sınıf veya arabirim türü ham tür değildir.

Ham türler eski kodda görünür, çünkü çok sayıda API sınıfı (Koleksiyon sınıfları gibi) JDK 5.0'dan önce genel değildir. Ham türleri kullanırken, temel olarak jenerik öncesi davranışa sahip Boxolursunuz - a size verir Object. Geriye dönük uyumluluk için parametreli bir türün ham türüne atanmasına izin verilir:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

Ancak parametrelenmiş bir türe ham tür atarsanız bir uyarı alırsınız:

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

Ayrıca, karşılık gelen genel türde tanımlanan genel yöntemleri çağırmak için ham bir tür kullanırsanız bir uyarı alırsınız:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // warning: unchecked invocation to set(T)

Uyarı, ham türlerin, güvenli olmayan kodun yakalanma zamanını erteleyerek genel tür denetimlerini atladığını gösterir. Bu nedenle, ham türleri kullanmaktan kaçınmalısınız.

Tür Silme bölümü, Java derleyicisinin ham türleri nasıl kullandığı hakkında daha fazla bilgi içerir.

İşaretlenmeyen Hata Mesajları

Daha önce belirtildiği gibi, eski kodu genel kodla karıştırırken, aşağıdakine benzer uyarı mesajlarıyla karşılaşabilirsiniz:

Not: Örnek.java, denetlenmeyen veya güvenli olmayan işlemler kullanır.

Not: Ayrıntılar için -Xlint: işaretlenmemiş olarak yeniden derleyin.

Bu, aşağıdaki örnekte gösterildiği gibi ham türlerde çalışan daha eski bir API kullanılırken gerçekleşebilir:

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

"İşaretlenmemiş" terimi, derleyicinin tür güvenliğini sağlamak için gereken tüm tür denetimlerini gerçekleştirmek için yeterli tür bilgisine sahip olmadığı anlamına gelir. Derleyici bir ipucu verse de, "denetlenmemiş" uyarısı varsayılan olarak devre dışıdır. Tüm "işaretlenmemiş" uyarıları görmek için -Xlint: işaretlenmemiş olarak yeniden derleyin.

Önceki örneği -Xlint ile yeniden derlemek: işaretsiz aşağıdaki ek bilgileri gösterir:

WarningDemo.java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<java.lang.Integer>
        bi = createBox();
                      ^
1 warning

İşaretlenmemiş uyarıları tamamen devre dışı bırakmak için -Xlint: -unchecked bayrağını kullanın. @SuppressWarnings("unchecked")Ek açıklama kontrolsüz uyarıları bastırır. @SuppressWarningsSözdizimine aşina değilseniz, Ek Açıklamalar sayfasına göz atın.

Orijinal kaynak: Java Eğiticileri


21

Java'daki "raw" türü, tür güvenli olmayan genel tür parametreleri yerine "raw" Nesneleriyle ilgilenen bir sınıftır.

Örneğin, Java jenerikleri kullanılabilir olmadan önce şöyle bir koleksiyon sınıfı kullanırsınız:

LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);

Nesnenizi listeye eklediğinizde, ne tür bir nesne olduğu umurumda değildir ve listeden aldığınızda, beklediğiniz türe açıkça atamanız gerekir.

Jenerikleri kullanarak "bilinmeyen" faktörünü kaldırırsınız, çünkü listede hangi tür nesnelerin gidebileceğini açıkça belirtmeniz gerekir:

LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);

Jenerikler ile get çağrısından gelen nesneyi yayınlamanız gerekmediğine dikkat edin, koleksiyon sadece MyObject ile çalışmak üzere önceden tanımlanmıştır. Bu gerçek jenerikler için ana itici faktördür. Çalışma zamanı hatalarının kaynağını derleme zamanında kontrol edilebilen bir şeye dönüştürür.


3
Daha spesifik olarak, bir ham tür, genel bir tür için tür parametrelerini atladığınızda elde ettiğiniz şeydir. Ham türler gerçekten sadece geriye dönük uyumluluk özelliğidir ve potansiyel olarak kaldırılmaya tabidir. Kullanarak benzer davranış elde edebilirsiniz? joker parametreler.
John Flatness

@zerocrates: benzer ama farklı! Kullanımı ?hala tip güvenliği sağlar. Cevabımda ele aldım.
poligeno

19
 private static List<String> list = new ArrayList<String>();

Type parametresini belirtmelisiniz.

Uyarı, jenerikleri desteklemek için tanımlanan türlerin ham formlarını kullanmak yerine parametrelendirilmesi gerektiğini önermektedir.

ListDestek jenerik tanımlanır: public class List<E>. Bu, derleme zamanı denetlenen birçok tür güvenli işleme izin verir.


3
Şimdi Java 7'de elmas çıkarımıyla değiştirildi -private static List<String> list = new ArrayList<>();
Ian Campbell

14

Ham tür nedir ve neden yeni kodda kullanılmamaları gerektiğini sık sık duyuyorum?

"Ham tür", parametreli tür (ler) i için tür bağımsız değişkenleri belirtmeden genel bir sınıfın kullanılmasıdır, örneğin Listyerine List<String>. Jenerikler Java'ya dahil edildiğinde, çeşitli sınıflar jenerikleri kullanacak şekilde güncellendi. Bu sınıfı "raw type" olarak kullanmak (type argümanı belirtmeden) eski kodun derlenmesine izin verdi.

"Ham tipler" geriye dönük uyumluluk için kullanılır. Yeni kodda kullanımları önerilmez çünkü bir sınıf argümanıyla genel sınıf kullanmak daha güçlü yazmaya izin verir, bu da kodun anlaşılabilirliğini artırabilir ve potansiyel sorunları daha erken yakalamaya yol açabilir.

Ham türleri kullanamıyorsak alternatif nedir ve nasıl daha iyidir?

Tercih edilen alternatif, uygun sınıf argümanıyla (örneğin List<String>) jenerik sınıfları amaçlandığı gibi kullanmaktır . Bu, programcının türleri daha spesifik olarak belirtmesine izin verir, gelecekteki koruyucular için bir değişkenin veya veri yapısının amaçlanan kullanımı hakkında daha fazla anlam ifade eder ve derleyicinin daha iyi tip güvenliği sağlamasına izin verir. Bu avantajlar birlikte kod kalitesini artırabilir ve bazı kodlama hatalarının girişini önlemeye yardımcı olabilir.

Örneğin, programcının 'names' adlı bir List değişkeninin yalnızca Dizeler içerdiğinden emin olmak istediği bir yöntem için:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error

1
Ah, kendi polygenelubricants"raw type" referanslarını stackoverflow.com/questions/2770111/… 'den kendi cevabım içine kopyalamak çok cazip , ama sanırım bunları kendi cevabında kullanmak üzere bırakacağım.
Bert F

1
Evet, temelde insanların stackoverflow'da ham türleri kullandığı her yerde bu segmenti kopyalayıp yapıştırıyorum ve nihayet bundan sonra başvurmak için sadece bir sorum olmaya karar verdim. Umarım bu topluluk için iyi bir katkıdır.
poligeno

1
@polygenelubricants fark ettim - aynı soruların bazılarını gördük :-)
Bert F

1
@ ha9u63ar: Gerçekten. Genel olarak kısa ve basit cevaplar en azından uzun ve kabul edilen cevaplar kadar iyidir.
displayName

"Daha güçlü şırınga" nedir?
carloswm85

12

Derleyici şunu yazmanızı istiyor:

private static List<String> list = new ArrayList<String>();

çünkü aksi takdirde, listsomutlaştırmayı new ArrayList<String>()anlamsız hale getirerek, istediğiniz herhangi bir türü ekleyebilirsiniz . Java jenerikleri yalnızca derleme zamanı özelliğidir, bu nedenle ile oluşturulan bir nesne new ArrayList<String>()mutlu bir şekilde kabul edilir Integerveya JFrame"ham tür" referansına atanırsa öğeler List- nesnenin kendisi hangi türleri içermesi gerektiği hakkında hiçbir şey bilmez, sadece derleyici yapar.


12

Burada kavramı açıklığa kavuşturabileceğiniz birden fazla durumu göz önünde bulunduruyorum

1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();

Dava 1

ArrayList<String> arrTür Nesnesine başvuran ArrayListtürden bir referans değişkendir . Bu sadece String tipi Object tutabileceği anlamına gelir.StringArralyListString

Bu bir Sıkı olan Stringbir Ham Tipi yüzden, Bir uyarı yükseltmek asla değildir.

    arr.add("hello");// alone statement will compile successfully and no warning.

    arr.add(23);  //prone to compile time error.
     //error: no suitable method found for add(int)

Durum 2

Bu durumda ArrayList<String> arrkatı bir türdür, ancak Nesneniz new ArrayList();ham bir türdür.

    arr.add("hello"); //alone this compile but raise the warning.
    arr.add(23);  //again prone to compile time error.
    //error: no suitable method found for add(int)

İşte arrSıkı bir tür. Yani, a eklerken derleme zamanı hatasını yükseltir integer.

Uyarı : - RawTür Nesnesi, StrictBaşvurulan Değişken türüne başvurulur ArrayList.

Vaka 3

Bu durumda ArrayList arrham türdür, ancak new ArrayList<String>();Nesneniz Katı türdür.

    arr.add("hello");  
    arr.add(23);  //compiles fine but raise the warning.

arrHam Tür olduğu için içine herhangi bir Nesne türü ekleyecektir .

Uyarı : - A StrictTipi Nesneye, rawDeğişken referanslı bir türe başvurulur.


8

Bir ham tipi bir eksikliğidir tür parametresi bir genel türü kullanırken.

Bir ekleme gibi, çalışma zamanı hataları neden olabilir çünkü Ham tipi kullanılmamalıdır doublebir olması gerekiyordu ne içine Setbir ints.

Set set = new HashSet();
set.add(3.45); //ok

Eşyaları alırken, Setne çıktığını bilmiyorsunuz. Diyelim ki bunların hepsinin olmasını bekliyorsunuz int, bunu yapıyorsunuz Integer; double3.45 geldiğinde çalışma zamanında istisna .

Türünüze bir type parametresi eklendiğinde Set, derleme hatası alırsınız. Bu önleyici hata, çalışma zamanı sırasında bir şey patlamadan önce sorunu gidermenizi sağlar (böylece zamandan ve emekten tasarruf sağlar).

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.

7

Ham türlerin sizi ısıtacağı başka bir durum:

public class StrangeClass<T> {
  @SuppressWarnings("unchecked")
  public <X> X getSomethingElse() {
    return (X)"Testing something else!";
  }

  public static void main(String[] args) {
    final StrangeClass<String> withGeneric    = new StrangeClass<>();
    final StrangeClass         withoutGeneric = new StrangeClass();
    final String               value1,
                               value2;

    // Compiles
    value1 = withGeneric.getSomethingElse();

    // Produces compile error:
    // incompatible types: java.lang.Object cannot be converted to java.lang.String
    value2 = withoutGeneric.getSomethingElse();
  }
}

Kabul edilen cevapta belirtildiği gibi, ham tür kodunda jeneriklere tüm desteği kaybedersiniz. Her tip parametresi silinmesine dönüştürülür (yukarıdaki örnekte sadece Object).


5

Ne söyleyerek aşağıdadır olmasıdır listbir olan Listunespecified nesnelerin. Java listenin içinde ne tür nesneler olduğunu bilmiyor. Daha sonra listeyi yinelemek istediğinizde, o öğenin özelliklerine (bu durumda, String) erişebilmek için her öğeyi yayınlamanız gerekir.

Genel olarak koleksiyonları parametreleştirmek için daha iyi bir fikirdir, bu nedenle dönüşüm sorunlarınız yoktur, yalnızca parametrelenmiş türdeki öğeleri ekleyebileceksiniz ve düzenleyiciniz size uygun yöntemleri seçecektir.

private static List<String> list = new ArrayList<String>();

4

öğretici sayfa .

Ham tür, herhangi bir tür bağımsız değişkeni olmayan genel bir sınıfın veya arabirimin adıdır. Örneğin, genel Box sınıfı göz önüne alındığında:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Parametreli bir Box türü oluşturmak için, T tipi resmi parametre için gerçek bir tür bağımsız değişkeni sağlarsınız:

Box<Integer> intBox = new Box<>();

Gerçek tür bağımsız değişkeni atlanırsa, ham bir Kutu türü oluşturursunuz:

Box rawBox = new Box();

2

Ham türlerden kaçının

Ham türler, bir tür parametresi belirtmeden genel bir türün kullanılmasını ifade eder.

Örneğin ,

Liste ham türken, List<String>parametrelenmiş türdür.

JDK 1.5'te jenerikler tanıtıldığında, ham türler yalnızca eski Java sürümleriyle geriye dönük uyumluluğu korumak için tutuldu. Ham türleri kullanmak hala mümkün olsa da,

Kaçınılmalıdır :

  • Genellikle oyuncu kadrosu gerekir
  • Bunlar güvenli değildir ve bazı önemli hata türleri yalnızca çalışma zamanında görünür.
  • Daha az ifade edicidirler ve parametreli tiplerle aynı şekilde kendi kendilerini belgelemezler Örnek

    import java.util.*;
    
    public final class AvoidRawTypes {
    
    void withRawType() {
    
        //Raw List doesn't self-document, 
        //doesn't state explicitly what it can contain
    
        List stars = Arrays.asList("Arcturus", "Vega", "Altair");
    
        Iterator iter = stars.iterator();
    
        while (iter.hasNext()) {
    
            String star = (String) iter.next(); //cast needed
    
            log(star);
        }
    
    }
    
    void withParameterizedType() {
    
        List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
    
        for (String star: stars) {
    
            log(star);
        }
    
    }
    
    private void log(Object message) {
    
        System.out.println(Objects.toString(message));
    
    }
    
    }

Referans için : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html


1

Bu sayfayı bazı örnek alıştırmalar yaptıktan ve tam olarak aynı şaşkınlığa kavuştuktan sonra buldum.

============== Bu koddan örnek olarak sağladım ===============

public static void main(String[] args) throws IOException {

    Map wordMap = new HashMap();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

====================== Bu kod için ========================

public static void main(String[] args) throws IOException {
    // replace with TreeMap to get them sorted by name
    Map<String, Integer> wordMap = new HashMap<String, Integer>();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
        Entry<String, Integer> entry =   i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

}

================================================== =============================

Daha güvenli olabilir ama felsefeyi bozmak 4 saat sürdü ...


0

Ham türler, ifade etmek istediklerinizi ifade ettiklerinde iyidir.

Örneğin, bir serileştirme işlevi bir List , ancak listenin öğe türünü bilmez. Yani Listburada uygun dönüş türüdür.


Kullanabilirsiniz ? tip parametresi olarak
Dániel Kis

Evet, ama bu yazmak için daha fazla ve ben daha fazla yazmaya karşıyım. :)
Stefan Reich
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.