2016-08-30 27 views
16

W klasie poniżej dostaję błąd kompilacji w Javie 8 z powodu niejednoznacznego wywołania this(). Z Javą 6 ta klasa jest jednak dobrze skompilowana. Wiem, że mógłbym to zmienić za pomocą metod fabrycznych i takich, ale dla rzeczywistej klasy, w której występuje problem, zdecydowanie wolałbym utrzymać obecny interfejs API na teraz.Niejednoznaczność konstruktora przy użyciu varargs w java 8

Czy ktoś może wymyślić sposób na rozwiązanie niejasności bez zmiany zewnętrznego interfejsu API?

public class Vararg8 { 

    public Vararg8(final Object... os) {} 

    public Vararg8(final boolean b, 
        final String s, 
        final int... is) {} 

    public Vararg8() { 
     this(true, "test", 4, 5, 6); 
    } 
} 

Odpowiedz

18

Można to zrobić przekazując wyraźny int[] tablicy:

public Vararg8() 
{ 
    this(true, "test", new int[]{4, 5, 6}); 
} 

Można zauważyć, że jest to nadal, w pewnym sensie, niejednoznaczne: co pan przeszedł jest wciąż zgodna z Object... konstruktor. Powodem tego jest to, że rozdzielczość metody idzie w różnych etapach, a dopiero ostatni etap pozwala na uwzględnienie parametrów varargs. Ponieważ używałeś jawnej tablicy, trafia ona w drugą dobrze, bez potrzeby rozszerzania varargs. Nie może trafić pierwszego bez rozszerzenia, więc nie będzie to brane pod uwagę do ostatniego etapu.

Patrz the appropriate JLS docs:

Pierwszy etap (§15.12.2.2) przeprowadza rozpoznawanie przeciążeniem nie dopuszczając boks lub rozpakowywanie konwersji, oraz zastosowanie zmiennego metodą arity wywołania. Jeśli podczas tej fazy nie zostanie znaleziona żadna odpowiednia metoda, przetwarzanie będzie kontynuowane do drugiej fazy.

Druga faza (§ 15.12.2.3) wykonuje rozładowanie, jednocześnie pozwalając na boksowanie i rozpakowywanie, ale nadal uniemożliwia użycie wywołania metody zmiennej arytem. Jeśli podczas tej fazy nie zostanie znaleziona żadna odpowiednia metoda, przetwarzanie będzie kontynuowane do trzeciej fazy.

Trzecia faza (§15.12.2.4) pozwala na łączenie przeciążania z metodami arytmetycznymi, boksem i rozpakowywaniem.

+0

Dzięki za wyjaśnienia i odniesienie do JLS.Nie wiedziałem o tej wielostopniowej rozdzielczości. – Ramses

3

Spróbuj tego:

public Vararg8() 
{ 
    this(true, "test", new int[]{4, 5, 6}); 
} 
2

Użyj wyraźne int tablicy powinno rozwiązać problem.

public Vararg8() { 
     this(true, "test",new int[]{ 4, 5, 6}); 
    } 
0

tablica znaków również rozwiązać problem

public Vararg8() { 
      this(true, "test".toCharArray(), 4, 5, 6); 
     } 
+0

Typy w przykładzie były tylko ilustracją, rzeczywisty kod używany głównie typy domeny ... – Ramses

1

Można użyć generycznych notowanym typów w czasie wykonywania, ale to będzie przekształcić je do postaci ramką. Oczywiście jest to kamikadze wydajności, jeśli robisz dużo arytmetyki lub masz do czynienia z dużą ilością prymitywów, ale pozostawiłbyś cały istniejący kod działający poprawnie.

Jeśli używasz już typów obiektów, to rozwiązanie to nic nie kosztuje.

to będzie wyglądać to lubi:

public<A extends Boolean, B extends String, C extends Integer> Disambiguate(final A booleanPar, 
             final B stringPar, 
             final C... integerPar) {System.out.println("Im in the specific one");} 

public<T extends Object> Disambiguate(final T... os) {System.out.println("Im in the general one");} 

public static void main(String[] args) { 
    new Disambiguate(true, "test", 4, 5, 6); 
} 

Można użyć rodzajowych dla „wstecznej kompatybilności” z 1,5 i wyżej i pozostawić wszystkie istniejący kod działa poprawnie i zrobić nowe API, które pozwoli uniknąć problemu w przyszłość.

Powiązane problemy