“Varargs parametresi için genel bir T dizisi oluşturuldu” derleyici uyarısını çözmek mümkün müdür?


153

Bu, söz konusu kodun basitleştirilmiş bir sürümüdür, bir genel sınıf genel tür parametreleriyle başka bir sınıf kullanır ve genel türlerden birini varargs parametreleri içeren bir yönteme geçirmesi gerekir:

class Assembler<X, Y> {
    void assemble(X container, Y... args) { ... }
}

class Component<T> {
    void useAssembler(T something) {

        Assembler<String, T> assembler = new Assembler<String, T>();

        //generates warning:
        // Type safety : A generic array of T is
        // created for a varargs parameter
        assembler.assemble("hello", something);
    }

}

Bu uyarıyla karşılaşmadan genel parametre boyunca bir varargs yöntemine geçmenin doğru bir yolu var mı?

Tabii ki

assembler.assemble("hello", new T[] { something });

genel diziler oluşturamadığınız için çalışmaz.


3
Tuhaf biri. Derleyici burada tam tip güvenliği sağlayabilmelidir.
erickson

3
Angelika Langer'in Java Generics ile ilgili SSS: angelikalanger.com/GenericsFAQ/FAQSections/…
Flow

Yanıtlar:


88

Eklemek dışında @SuppressWarnings("unchecked"), sanmıyorum.

Bu hata raporunda daha fazla bilgi vardır, ancak genel tür dizilerinden hoşlanmamak için derleyiciye kadar kaynar.


3
@SuppressWarnings ("işaretlenmemiş") önlemek istedim bahsetmeyi unuttum. Bu hata raporu bana biraz umut veriyor!
matt b

3
Joshua Bloch'un Etkili Java'ya koyduğu gibi: "Jenerik ve dizileri karıştırmayın."
Timmos

20
o zaman, dolaysız: Varargs'ı Generics ile kullanmayın! Doğru ... varargs'ı Array değil Array ile eşleme kararı java'yı sonsuza dek sokmaya devam edecektir. Bay Gosling iyi iş çıkardı.
bernstein

57

Tom Hawtin bir yorumda dikkat çekti, ancak daha açık olmak gerekirse: evet, bunu beyan sitesinde (potansiyel olarak çok sayıda çağrı sitesi yerine) çözebilirsiniz: JDK7'ye geçin.

Joseph Darcy'nin blog gönderisinde görebileceğiniz gibi , Project Coin çalışması, Java 7 için bazı küçük artımlı dil iyileştirmelerini seçmek için Bob Lee'nin@SuppressWarnings("varargs") yöntem tarafında olduğu gibi bir şeyin bu uyarıyı bilindiği durumlarda ortadan kaldırmasına izin verme teklifini kabul etti. kasa.

Bu, bu taahhüt ile OpenJDK'da uygulanmıştır .

Bu, projeniz için yararlı olabilir veya olmayabilir (birçok kişi JVM'nin yayın öncesi kararsız bir sürümüne geçmek için mutlu olmaz!) Ama belki de - veya belki de bu soruyu daha sonra bulan bir kişi (JDK7 bittikten sonra) ) yararlı bulacaktır.


7
Bahsedilen Project Coin özelliği kullanıma sunuldu - Java 7'deki @SafeVarargs sayfasına bakın
George Hawkins

Bob'un teklifindeki Alternatif E cazip geliyor.
Christopher Perry

Java 8, @SuppressWarnings ("varargs") yerine @SafeVarargs kullanıyor gibi görünüyor
Paul Wintz

17

Akıcı bir arayüzün peşindeyseniz, oluşturucu desenini deneyebilirsiniz. Varargs kadar özlü değil, tip güvenlidir.

Statik jenerik tipli bir yöntem, yapıcıyı kullanırken kazan plakasının bir kısmını ortadan kaldırırken, tip güvenliğini koruyabilir.

Oluşturucu

public class ArgBuilder<T> implements Iterable<T> {

    private final List<T> args = new ArrayList<T>();

    public ArgBuilder<T> and(T arg) {
        args.add(arg);
        return this;
    }

    @Override
    public Iterator<T> iterator() {
        return args.iterator();
    }

    public static <T> ArgBuilder<T> with(T firstArgument) {
        return new ArgBuilder<T>().and(firstArgument);
    }
}

Kullanma

import static com.example.ArgBuilder.*;

public class VarargsTest {

    public static void main(String[] args) {
        doSomething(new ArgBuilder<String>().and("foo").and("bar").and("baz"));
        // or
        doSomething(with("foo").and("bar").and("baz"));
    }

    static void doSomething(Iterable<String> args) {
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}

1
Kompozisyonun gücü. Bunu varargs'dan daha çok seviyorum, daha etkileyici.
Christopher Perry

1
@ChristopherPerry de kod tabanınızı da düşünmelisiniz. Altta yatan Collection(bu durumda an ArrayList) arayana zorlanırken LinkedList, a'nın daha uygun olduğunu veya değişmez bir dizinin kendisinin (OP sorusundaki varargs gibi) olduğunu bilebilirler. Uzman olmayan bir kullanım durumunda bu uygun olabilir, ancak sadece bunu çevreleyen koda ve ihtiyaçlarınıza bağlı olarak bir şekilde bir sınırlama olduğuna dikkat edin.
searchengine27

5

Parametreleri vararg yöntemi çağrısında açıkça Nesne'ye aktarmak derleyiciyi @SuppressWarnings'e başvurmadan mutlu edecektir.

public static <T> List<T> list( final T... items )
{
    return Arrays.asList( items );
}

// This will produce a warning.
list( "1", 2, new BigDecimal( "3.5" ) )

// This will not produce a warning.
list( (Object) "1", (Object) 2, (Object) new BigDecimal( "3.5" ) )

// This will not produce a warning either. Casting just the first parameter to 
// Object appears to be sufficient.
list( (Object) "1", 2, new BigDecimal( "3.5" ) )

Burada sorun derleyici oluşturmak için ne tür somut bir dizi anlamaya ihtiyacı olduğuna inanıyorum. Yöntem genel değilse, derleyici yöntemden tür bilgisini kullanabilir. Yöntem genel ise, çağırmada kullanılan parametrelere göre dizi türünü anlamaya çalışır. Parametre türleri homojen ise, bu görev kolaydır. Değişirlerse, derleyici bence çok zeki olmaya çalışır ve sendika tipi bir jenerik dizi oluşturur. O zaman sizi bu konuda uyarmaya mecbur hissediyor. Yazı daha iyi daraltılamadığında Object [] oluşturmak daha basit bir çözüm olurdu. Yukarıdaki çözüm tam da bunu zorlar.

Bunu daha iyi anlamak için, yukarıdaki list2 yöntemine kıyasla yukarıdaki liste yöntemine yönelik çağrılarla oynayın.

public static List<Object> list2( final Object... items )
{
    return Arrays.asList( items );
}

Bu da işe yarar, örneğin: Iterator <?> İt = Arrays.asList ((Object) t) .iterator; if (if, hasNext ()) {class = it.next (). getClass (); } örneğin bir nesnenin sınıfını bilinmeyen türde bir diziden çıkarmak için.
ggb667

2

Java 7'den beri @SafeVarargs yöntemine ekleyebilirsiniz ve istemci koduna ek açıklama eklemeniz gerekmez .

class Assembler<X, Y> {

    @SafeVarargs
    final void assemble(X container, Y... args) {
        //has to be final...
    }
}

1

Yöntemleri aşırı yükleyebilirsiniz. Bu sorununuzu çözmez, ancak uyarı sayısını en aza indirir (ve evet, bu bir hack!)

class Assembler<X, Y> {
  void assemble(X container, Y a1) { ... }
  void assemble(X container, Y a1, Y a2) { ... }
  void assemble(X container, Y a1, Y a2, Y a3) { ... }
  void assemble(X container, Y a1, Y a2, Y a3, Y a4) { ... }
  void assemble(X container, Y... args) { ... }
}

23
Ew. Bu tam olarak varargların önlemesi gereken bir tür hack'tir.
Amanda S

1
Bu geçerli bir yaklaşım olabilir, örneğin, Guava'nın ImmutableSet.of dosyasına bir göz atın .
Jonathan

1

Çözmek çok kolay bir problem: Kullanın List<T>!

Referans tipi dizilerden kaçınılmalıdır.

Java'nın geçerli sürümünde (1.7), @SafeVargsuyarıyı arayandan kaldıracak yöntemi işaretleyebilirsiniz . Buna dikkat edin ve eski diziler olmadan hala daha iyisiniz.

Ayrıca Varargs Metodları ile Reifiable Formal Parametreleri Kullanılırken Geliştirilmiş Derleyici Uyarıları ve Hataları bölümüne bakın .


6
bu bir varargs parametresiyle kaçınılmazdır, değil mi?
matt b

4
JDK7'nin, uyarı bastırmanın kullanımından ziyade varargs yöntemi bildirimine geçmesine izin vermesi için bir teklif var.
Tom Hawtin - taktik

11
Bu, yazarın sorusunun önemli bir yönünü tamamen göz ardı eder - varargs parametreleri bir dizi oluşturur ve bu uyarıyı üretir.
Daniel Yankowsky

2
@Tom Hawtin - tackline ile hemfikirim. Ayrıntılar için bkz. Bloch << Etkili Java >> Madde 25: Dizileri listeler.
Stan Kurilin

2
Bu konuda genel olarak Bloch ile aynı fikirdeyim, ancak varargs bu kuralın açık bir istisnası ...
Joeri Hendrickx

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.