2016-08-30 5 views
16

В приведенном ниже классе я получаю ошибку компиляции с Java 8 из-за неоднозначного вызова this(). Тем не менее, с Java 6 этот класс скомпилирован. Я знаю, что могу реорганизовать это с использованием заводских методов и т. Д., Но для фактического класса, где возникает проблема, я бы предпочел поддерживать текущий API на данный момент.Неопределенность конструктора с varargs в java 8

Может ли кто-нибудь подумать о способе устранения двусмысленности без изменения внешнего 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); 
    } 
} 

ответ

18

Вы можете сделать это путем пропускания явно int[] массива:

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

Вы могли бы заметить, что это до сих пор, в каком-то смысле, неоднозначно: что вы прошли по-прежнему совместит с Object... конструктор. Причина этого в том, что разрешение метода идет в разные этапы, и только последний этап позволяет рассмотреть параметры varargs. Поскольку вы использовали явный массив, он попадает во второй, без необходимости расширения varargs. Он не может попасть в первый, без расширения varargs, так что это не будет рассматриваться до финальной стадии.

См the appropriate JLS docs:

На первом этапе (§15.12.2.2) выполняет разрешение перегрузки, не допуская бокс или распаковку преобразования, или использование переменного метода арности вызова. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до второй фазы.

Вторая фаза (§15.12.2.3) выполняет разрешение перегрузки при разрешении бокса и распаковки, но все же исключает использование вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до третьей фазы.

Третий этап (§15.12.2.4) позволяет комбинировать перегрузку с методами переменной arity, боксом и распаковкой.

+0

Спасибо за разъяснение и ссылку на JLS.Я не знал об этом многоступенчатом разрешении. – Ramses

3

Попробуйте это:

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

Используйте явное целочисленный массив должен решить вашу проблему.

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

массив символов также решить вашу проблему

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

Типы в примере были всего лишь иллюстрацией, фактический код использовал в основном типы домена ... – Ramses

1

Вы можете использовать общий для вывода типов во время выполнения, но это превратит их в штучной форме. Это, конечно, производительность kamikaze, если вы делаете там много арифметики или должны загружать много примитивов, но оставите весь существующий код работать нормально.

Если вы используете объекты типа уже, то это решение не будет стоить вам ничего.

Это будет выглядеть понравилось:

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); 
} 

Вы могли бы использовать дженерики для «обратной совместимости» с 1,5 и выше, и оставить все существующий код работает отлично и сделать новый Апи, что позволит избежать проблемы в будущее.