Java'da değişken argümanları olan bir yönteme bir dizi bağımsız değişken olarak iletebilir miyim?


276

Gibi bir işlev oluşturmak istiyorum:

class A {
  private String extraVar;
  public String myFormat(String format, Object ... args){
    return String.format(format, extraVar, args);
  }
}

Burada sorun olduğunu argsolarak kabul edilir Object[]yöntemde myFormatve böylece tek bir argümandır String.formatben her isterim ederken, Objectiçinde argsyeni bir argüman olarak geçirilecek. Yana String.formatda değişken bağımsız değişken içeren bir yöntemdir, bu mümkün olmalıdır.

Bu mümkün değilse, böyle bir yöntem var String.format(String format, Object[] args)mı? Bu durumda, I prepend olabilir extraVariçin argsyeni bir dizi kullanarak ve bu yöntemle geçmektedir.


8
Bu sorunun neden "bu geçerli" bir soru olduğunu merak edemiyorum. Sadece dener misin? Aşırıya kaçmayın, kendinize iyiden daha fazla zarar vereceksiniz.
'22

21
yeterince doğru, bu kolayca test edilebilirdi. Ancak, böyle bir soru hakkında güzel bir şey, konuyu açığa çıkarması ve ilginç cevaplar istemesidir.
akf

2
Aslında, yönteme argüman olarak dizi argüman geçmek niyetiyle yukarıdaki kodu denedim. Ancak, önce argümanlara extraVar eklemem gerektiğini fark etmedim. Değişken argümanlarının bir dizi olarak ele alındığını bildiğinizde (yöntemin dışında bile), bu elbette oldukça mantıklıdır.
user362382

Yanıtlar:


181

Variadic yöntemin temel tipi function(Object... args) olan function(Object[] args) . Sun, geriye dönük uyumluluğu korumak için bu şekilde varargs ekledi.

Bu nedenle, sadece başının başına extraVargelip argsçağırabilirsiniz String.format(format, args).


1
X[]Bir yönteme tür argümanının aktarılması x(X... xs)Eclipse'de şu uyarıyı verir:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
Luke Hutchison

318

Evet, a T...sadece bir sözdizimsel şekerdir T[].

JLS 8.4.1 Format parametreleri

Listedeki son resmi parametre özeldir; bu türden sonra bir elips ile gösterilen değişken bir arity parametresi olabilir .

Son resmi parametre tipte bir değişken arity parametresiyse, tipte Tresmi bir parametre tanımlandığı kabul edilir T[]. Yöntem bu durumda değişken bir arity yöntemidir. Aksi takdirde, sabit bir arity yöntemidir. Bir değişken arity yönteminin çağrılması, resmi parametrelerden daha fazla gerçek argüman ifadesi içerebilir. Değişken arity parametresinden önceki biçimsel parametrelere karşılık gelmeyen tüm gerçek argüman ifadeleri değerlendirilecek ve sonuçlar yöntem çağrısına geçirilecek bir diziye kaydedilecektir.

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

public static String ezFormat(Object... args) {
    String format = new String(new char[args.length])
        .replace("\0", "[ %s ]");
    return String.format(format, args);
}
public static void main(String... args) {
    System.out.println(ezFormat("A", "B", "C"));
    // prints "[ A ][ B ][ C ]"
}

Ve evet, yukarıdaki mainyöntem geçerlidir, çünkü tekrar, String...sadece String[]. Ayrıca, diziler kovaryant String[]olduğu için a bir Object[], yani ezFormat(args)her iki şekilde de çağırabilirsiniz .

Ayrıca bakınız


Varargs Gotchas # 1: Geçen null

Vararların nasıl çözüldüğü oldukça karmaşıktır ve bazen sizi şaşırtacak şeyler yapar.

Bu örneği düşünün:

static void count(Object... objs) {
    System.out.println(objs.length);
}

count(null, null, null); // prints "3"
count(null, null); // prints "2"
count(null); // throws java.lang.NullPointerException!!!

Varargs'ın nasıl çözüldüğüne bağlı olarak, son ifade objs = nullelbette neden NullPointerExceptionolur objs.length. nullBir varargs parametresine bir bağımsız değişken vermek istiyorsanız , aşağıdakilerden birini yapabilirsiniz:

count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"

İlgili sorular

Aşağıdakiler, insanların varargs ile uğraşırken sordukları bazı soruların bir örneğidir:


Vararg Gotchas # 2: Ekstra argümanlar ekleme

Bildiğiniz gibi, aşağıdakiler "işe yaramaz":

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(myArgs, "Z"));
    // prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"

Çünkü varargs çalışma şekli, ezFormataslında 2 argüman alır, ilki a String[], ikincisi a String. Bir diziyi varargs'e geçiriyorsanız ve öğelerinin bağımsız değişkenler olarak tanınmasını istiyorsanız ve ayrıca bir bağımsız değişken eklemeniz gerekiyorsa , ekstra öğeyi barındıran başka bir dizi oluşturmaktan başka seçeneğiniz yoktur .

İşte bazı yararlı yardımcı yöntemler:

static <T> T[] append(T[] arr, T lastElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    arr[N] = lastElement;
    return arr;
}
static <T> T[] prepend(T[] arr, T firstElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    System.arraycopy(arr, 0, arr, 1, N);
    arr[0] = firstElement;
    return arr;
}

Şimdi aşağıdakileri yapabilirsiniz:

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(append(myArgs, "Z")));
    // prints "[ A ][ B ][ C ][ Z ]"

    System.out.println(ezFormat(prepend(myArgs, "Z")));
    // prints "[ Z ][ A ][ B ][ C ]"

Varargs Gotchas # 3: Bir dizi ilkel geçen

"Çalışmıyor":

    int[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ [I@13c5982 ]"

Varargs yalnızca referans türleriyle çalışır. Otomatik boks ilkel dizi için geçerli değildir. Aşağıdaki işler:

    Integer[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ 1 ][ 2 ][ 3 ]"

2
Object ... variadic parametrelerini kullanmak, derleyici, ilkel bir argümanın bile Object'e otomatik olarak kutulanabileceği imzalar arasındaki belirsizliği tanımladığı için ek imzaların kullanılmasını zorlaştırır.
eel ghEEz

7
Eksik bir gotcha var: yönteminizin Object ... türünde son bir parametresi varsa ve örneğin String [] 'i geçerek çağırırsanız. Derleyici, dizinizin varargs'ın ilk öğesi mi yoksa tüm varargs'ın karşılığı mı olduğunu bilmiyor. Seni uyaracak.
Snicolas

X[]Bir yönteme tür argümanının aktarılması x(X... xs)Eclipse'de şu uyarıyı verir:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
Luke Hutchison

23

Bir diziyi geçmek sorun değil - aslında aynı şey anlamına geliyor

String.format("%s %s", "hello", "world!");

aynıdır

String.format("%s %s", new Object[] { "hello", "world!"});

Sadece sözdizimsel şeker - derleyici ilkini ikinciye dönüştürür, çünkü alttaki yöntem vararg parametresi için bir dizi bekler .

Görmek


4

jasonmp85 farklı bir diziye geçme konusunda haklı String.format. Bir dizinin boyutu oluşturulduktan sonra değiştirilemez, bu nedenle mevcut diziyi değiştirmek yerine yeni bir dizi geçirmeniz gerekir.

Object newArgs = new Object[args.length+1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = extraVar; 
String.format(format, extraVar, args);

1

Aynı sorunu yaşıyordum.

String[] arr= new String[] { "A", "B", "C" };
Object obj = arr;

Ve sonra nesneyi varargs argümanı olarak geçti. İşe yaradı.


2
Lütfen bunu da ekleyin.
Mathews Sunny
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.