Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Методы с varargs (...
) имеют самый низкий приоритет, когда компилятор определяет, какой перегруженный метод выбрать. Поэтому TestOverload(int i)
выбирается над TestOverload(char... c)
, когда вы вызываете TestOverload
с одним параметром char
'a'
, так как char
можно автоматически повысить до int
.
blockquote>
- Первая фаза (§15.12.2.2) выполняет разрешение перегрузки без разрешения преобразования бокса или распаковки или использования метода переменной arity призывание. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до второй фазы. Это гарантирует, что любые вызовы, которые были действительны на языке программирования Java до Java SE 5.0, не считаются неоднозначными в результате внедрения методов переменной arity, неявного бокса и / или распаковки. Однако объявление метода переменной arity (§8.4.1) может изменить метод, выбранный для выражения вызова метода данного метода, поскольку метод переменной arity рассматривается как метод фиксированной arity в первой фазе. Например, объявление m (Object ...) в классе, который уже объявляет m (Object), приводит к тому, что m (Object) больше не выбирается для некоторых выражений вызова (таких как m (null)), как m (Object []) ) более конкретно.
- Вторая фаза (§15.12.2.3) выполняет разрешение перегрузки при разрешении бокса и распаковки, но все же исключает использование вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до третьей фазы. Это гарантирует, что метод никогда не выбирается с помощью вызова метода переменной arity, если он применим посредством вызова метода фиксированной arity.
- Третья фаза (§15.12.2.4) позволяет перегрузке сочетаться с различными способами arity, бокс , и unboxing.
EDIT:
Вы хотите заставить компилятор вызвать конструктор
TestOverload(char... c)
, вы можете перейти к вызову конструктора achar[]
:new TestOverload (new char[] {'a'});
Я взял код из этой ссылки и изменил некоторые его части:
public static void main(String[] args) {
Byte i = 5;
byte k = 5;
aMethod(i, k);
}
//method 1
static void aMethod(byte i, Byte k) {
System.out.println("Inside 1");
}
//method 2
static void aMethod(byte i, int k) {
System.out.println("Inside 2");
}
//method 3
static void aMethod(Byte i, Byte k) {
System.out.println("Inside 3 ");
}
//method 4
static void aMethod(Byte i, Byte ... k) {
System.out.println("Inside 4 ");
}
Компилятор дает ошибку (метод неоднозначен для типа Overloading) для методов 1, 2 и 3, но не 4 (почему?)
Ответ заключается в механизме, который java использует для сопоставления вызовов методов методам. Механизм выполняется в три этапа, в каждой фазе, если он находит метод совпадения:
+ фаза первая: используйте расширение, чтобы найти метод сопоставления (не найдено совпадающих методов)
+ второй этап: (также) использовать бокс / unboxing для поиска метода сопоставления (метод 1,2 и 3)
+ фаза три: (также) использовать var args (метод 4 соответствует!) [/ g6]
Да, это ожидаемое поведение. Приоритет для вызова метода выглядит следующим образом:
Ниже выдержки из Java docs , связанных с тем же: -
Процесс определения применимости начинается с определения потенциально применимых методов (§15.12.2.1).
Остальная часть процесса разделена на три этапа, чтобы обеспечить совместимость с версиями языка программирования Java до Java SE 5.0. Фазы:
Первая фаза (§15.12.2.2) выполняет разрешение перегрузки без разрешения преобразования бокса или распаковки или использования вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до второй фазы.
Это гарантирует, что любые вызовы, которые были действительны на языке программирования Java до Java SE 5.0, не считаются неоднозначными в результате внедрение методов переменной arity, неявного бокса и / или распаковки. Однако объявление метода переменной arity (§8.4.1) может изменить метод, выбранный для выражения вызова метода данного метода, поскольку метод переменной arity рассматривается как метод фиксированной arity в первой фазе. Например, объявление m (Object ...) в классе, который уже объявляет m (Object), приводит к тому, что m (Object) больше не выбирается для некоторых выражений вызова (таких как m (null)), как m (Object []) ) более конкретно.
Вторая фаза (§15.12.2.3) выполняет разрешение перегрузки при разрешении бокса и распаковки, но все же исключает использование вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до третьей фазы.
Это гарантирует, что метод никогда не выбирается при вызове метода переменной arity, если он применим посредством вызова метода фиксированной arity.
Третий этап (§15.12.2.4) позволяет комбинировать перегрузку с использованием методов переменной arity, бокса и распаковки.
blockquote>
Твердые советы от Джошуа Блоха (Эффективная Java, 2-е изд.):
"только выбирают в качестве аргументов для перегруженного метода те, которые имеют -радиционно разные типы."
blockquote>Объект с радикально отличающимся типом - это тот, который нельзя разумно отличить от другого типа аргументов. Следуя этому правилу, вы можете сэкономить часы отладки таинственной ошибки, которая может произойти, когда компилятор во время компиляции выбирает перегрузку метода, которую вы не ожидали.
Ваши строки кода нарушают это правило и открывают дверь для ошибок:
public TestOverload(int i){System.out.println("Int");} public TestOverload(char... c){System.out.println("char");}
A
char
является взаимозависимым сint
, поэтому единственный способ предсказать, что произойдет с вызовами, - это перейти к Спецификации языка Java и прочитать несколько тайные правила о том, как разрешаются перегрузки.К счастью, эта ситуация не должна нуждаться в исследовании JLS. Если у вас есть аргументы, которые не сильно отличаются друг от друга, возможно, лучшим вариантом является , а не перегрузка . Дайте методам разные имена, чтобы не было возможности для ошибки или путаницы со стороны любого, кому может понадобиться поддерживать код.
Время - деньги.
int max(int x, int y)
и long max(long x, long y)
- отлично.
– CodesInChaos
9 September 2015 в 10:15
new TestOverload (new char[] {'a'});
– Eran 9 September 2015 в 05:31new TestOverload(new char[] {'a'})
– Erwin Bolwidt 9 September 2015 в 05:32public TestOverload(char c){ this(new char[]{ c }); }
, вызов конструктора станет более приятным:new TestOverload('a')
, как захотел OP. – Justin 10 September 2015 в 05:41