Bu derlemez, herhangi bir öneri takdir edilir.
...
List<Object> list = getList();
return (List<Customer>) list;
Derleyici diyor ki: List<Object>
dönüştürülemiyorList<Customer>
Bu derlemez, herhangi bir öneri takdir edilir.
...
List<Object> list = getList();
return (List<Customer>) list;
Derleyici diyor ki: List<Object>
dönüştürülemiyorList<Customer>
Yanıtlar:
her zaman herhangi bir nesneyi önce Object'e yukarı çevirerek herhangi bir türe çevirebilirsiniz. Senin durumunda:
(List<Customer>)(Object)list;
çalışma zamanında listenin Müşteri nesnelerinden başka hiçbir şey içermediğinden emin olmalısınız.
Eleştirmenler, bu tür bir atamanın kodunuzla ilgili yanlış bir şeyi gösterdiğini söylüyor; Bundan kaçınmak için tür bildirimlerinizi değiştirebilmelisiniz. Ancak Java jenerikleri çok karmaşık ve mükemmel değil. Bazen, çalışma zamanı türlerini çok iyi bilseniz ve ne yapmaya çalıştığınızın güvenli olduğunu bilseniz bile, derleyiciyi tatmin edecek güzel bir çözüm olup olmadığını bilemezsiniz. Bu durumda, gerektiği gibi ham dökümü yapın, böylece ev için işten ayrılabilirsiniz.
@SuppressWarnings("unchecked")
. (List)
Bunun yerine, yukarı doğru da yayınlayabileceğinizi unutmayın (Object)
.
Bunun nedeni, Müşteri bir Nesne olmasına rağmen, Müşteri Listesi'nin Nesne Listesi olmamasıdır . Öyleyse, herhangi bir nesneyi Müşteri listesine koyabilirsiniz .
.Cast<T>()
, diğeri çağrılır .OfType<T>()
. İlki, her bir öğe üzerinde bir cast gerçekleştirirken (istenen istisnaları atarak) ikincisi, dönüştürülemeyen öğeleri filtreler (böylece kullanım senaryonuza bağlı olarak birini seçersiniz).
instanceof
Müşteri değilse ne olur ?
Diğer kodunuza bağlı olarak, en iyi cevap değişebilir. Deneyin:
List<? extends Object> list = getList();
return (List<Customer>) list;
veya
List list = getList();
return (List<Customer>) list;
Ancak, bu tür kontrolsüz yayınların yapılmasının tavsiye edilmediğini unutmayın.
Java 8 Akışı ile :
Bazen kaba kuvvet dökümü iyidir:
List<MyClass> mythings = (List<MyClass>) (Object) objects
Ama işte daha çok yönlü bir çözüm:
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
Bir sürü faydası var, ancak bir tanesi, ne içerdiğinden emin olamazsanız, listenizi daha zarif bir şekilde yayınlayabilmenizdir:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
FluentIterable
benim için çalıştı.
Çift alçı kullanabilirsiniz.
return (List<Customer>) (List) getList();
Java programcısı olmadığımı unutmayın, ancak .NET ve C # 'da bu özelliğe kontravaryans veya kovaryans denir. Henüz bunlara girmedim, çünkü .NET 4.0'da yeni olduklarından, sadece beta olduğu için kullanmıyorum, bu yüzden iki terimden hangisinin probleminizi tanımladığını bilmiyorum, ancak açıklamama izin verin bununla ilgili teknik sorun.
Rol almanıza izin verildiğini varsayalım. Not, döküm diyorum , çünkü söylediğiniz buydu, ancak mümkün olabilecek iki işlem vardır: döküm ve dönüştürme .
Dönüştürme, yeni bir liste nesnesi alacağınız anlamına gelir, ancak çevrim diyorsunuz, bu da bir nesneyi geçici olarak başka bir tür olarak ele almak istediğiniz anlamına gelir.
İşte bununla ilgili sorun.
Aşağıdakilere izin verilseydi ne olurdu (not, dökümden önce nesnelerin listesinin aslında yalnızca Müşteri nesnelerini içerdiğini varsayıyorum, aksi takdirde, java'nın bu varsayımsal sürümünde bile cast çalışmaz):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
Bu durumda, bu, müşteri olmayan bir nesneyi müşteri olarak ele almaya çalışır ve bir noktada, listenin içinde veya atamadan bir çalışma zamanı hatası alırsınız.
Bununla birlikte, jeneriklerin size koleksiyonlar gibi güvenli veri türleri vermesi beklenir ve 'garantili' kelimesini etrafa saçmayı sevdikleri için, aşağıdaki sorunlarda bu tür dökümlere izin verilmez.
.NET 4.0'da (biliyorum, sorunuz java hakkındaydı), buna bazı çok özel durumlarda izin verilecektir . derleyicinin yaptığınız işlemlerin güvenli olduğunu garanti edebildiği , ancak genel anlamda bu tür yayınlama izin. Aynı şey java için de geçerli, ancak java diline ortak ve kontravaryans getirme planlarından emin değilim.
Umarım, benden daha iyi java bilgisine sahip biri size java geleceği veya uygulamasıyla ilgili ayrıntıları söyleyebilir.
Başka bir yaklaşım, bir java 8 akışı kullanmak olacaktır.
List<Customer> customer = myObjects.stream()
.filter(Customer.class::isInstance)
.map(Customer.class::cast)
.collect(toList());
List<Customer> cusList = new ArrayList<Customer>();
for(Object o: list){
cusList.add((Customer)o);
}
return cusList;
list.stream().forEach(x->cusList.add((Customer)x))
return cuslist;
Yapamazsın çünkü List<Object>
veList<Customer>
aynı miras ağacında değilsiniz.
List<Customer>
Sınıfınıza, bir alan alan yeni bir kurucu ekleyebilir List<Object>
ve ardından her Object
birini a'ya aktaran Customer
ve koleksiyonunuza ekleyen listeyi yineleyebilirsiniz . Arayan kişi List<Object>
başka bir şey içermiyorsa geçersiz bir atama istisnasının meydana gelebileceğini unutmayın.Customer
.
Genel listelerin amacı, onları belirli türlerle sınırlandırmaktır. İçinde herhangi bir şey bulunabilecek bir listeyi (Siparişler, Ürünler vb.) Alıp yalnızca Müşteri alabilecek bir listeye sıkıştırmaya çalışıyorsunuz.
En iyi bahsiniz, yeni bir tane oluşturmak List<Customer>
, üzerinde yinelemek List<Object>
, her öğeyi yeni listeye eklemek ve onu iade etmektir.
Başkalarının da belirttiği gibi, a List<Object>
, a olmadığı için onları savurgan bir şekilde kullanamazsınız List<Customer>
. Yapabileceğiniz şey, listede yerinde tür denetimi yapan bir görünüm tanımlamaktır. Google Koleksiyonlarını kullanarak :
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
Yukarıdaki Bozho ile benzer. Bu yöntemle (kendimden hoşlanmasam da) burada bazı geçici çözümler yapabilirsiniz:
public <T> List<T> convert(List list, T t){
return list;
}
Evet. Listenizi talep ettiğiniz jenerik türüne aktaracaktır.
Yukarıdaki verilen durumda, aşağıdaki gibi bazı kodlar yapabilirsiniz:
List<Object> list = getList();
return convert(list, new Customer());
Listeyle ne yapmak istediğinize bağlı olarak, onu bir List<Customer>
. Listeye yalnızca Customer
nesne eklemek istiyorsanız , bunu aşağıdaki gibi bildirebilirsiniz:
...
List<Object> list = getList();
return (List<? super Customer>) list;
Bu yasal (evet, sadece yasal değil, doğru - liste "Müşteriye bir tür süper tiptir") ve listeyi yalnızca listeye nesneler ekleyecek bir yönteme geçirecekseniz, o zaman yukarıdaki bunun için genel sınırlar yeterlidir.
Öte yandan, listeden nesneleri almak ve onları güçlü bir şekilde Müşteri olarak yazmak istiyorsanız - o zaman şansınız kalmaz ve haklı olarak öyle. Liste, List<Object>
içeriklerin müşteri olduğuna dair bir garanti olmadığından, geri alma konusunda kendi dökümünüzü sağlamanız gerekir. (Ya da gerçekten, kesinlikle, iki kat emin olun ki, listenin yalnızca Customers
diğer cevaplardan birinden bir çift örnek içerecek ve kullanacaktır, ancak bu konuda jeneriklerden elde ettiğiniz derleme zamanı tür güvenliğini tamamen alt ettiğinizi fark edin. durum).
Genel olarak konuşursak, bir yöntem yazarken kabul edilebilecek mümkün olan en geniş genel sınırları dikkate almak her zaman iyidir, eğer bir kütüphane yöntemi olarak kullanılacaksa iki katına çıkar. Yalnızca bir listeden okuyacaksanız , örneğin List<? extends T>
yerine kullanın List<T>
- bu, arayanlara iletebilecekleri argümanlarda çok daha fazla kapsam sağlar ve sizin adınıza benzer önlenebilir sorunlarla karşılaşma olasılıklarının daha düşük olduğu anlamına gelir. burada yaşıyoruz.