NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Разрешение метода говорит, что лучше ближе . См. Сообщение в блоге для точных правил.
Что означает более близкое? Компилятор увидит, может ли он найти точное совпадение, если он не может найти по какой-либо причине, он найдет следующие возможные совместимые методы и т. Д.
Давайте сначала сделаем этот метод компиляцией, удалив ограничение SomeInterface
.
public static class ExtensionMethods
{
public static void Method<T>(this T parameter) //where T : SomeInterface
{ }
public static void Method<T>(this IEnumerable<T> parameter) //where T : SomeInterface
{ }
}
Теперь компилятор с удовольствием компилирует и замечает, что оба вызова метода идут до Method(T)
, а не Method(IEnumerable<T>)
. Почему?
Поскольку Method(T)
ближе в том смысле, что может принимать любой тип в качестве параметра, а также не требует никакого преобразования.
Почему
blockquote>Method(IEnumerable<T>)
не ближе?Это потому, что у вас есть тип времени компиляции переменной как
List<T>
, поэтому для него требуется преобразование ссылок отList<T>
доIEnumerable<T>
. Который ближе, но не делает никаких конверсий вообще.Вернемся к вашему вопросу.
Почему
blockquote>instances.Method();
не компилируется?Опять же, как было сказано ранее для использования
Method(IEnumerable<T>)
, нам нужно какое-то ссылочное преобразование, так что очевидно, что это не ближе. Теперь у нас остается только один метод, который очень близокMethod<T>
. Но проблема в том, что вы ограничили его с помощьюSomeInterface
, и, очевидно,List<SomeImplementation>()
не конвертируется вSomeInterface
.Проблема (угадывание) проверка общих ограничений происходит после того, как компилятор выбирает более близкую перегрузки. Это делает недействительной выбранную лучшую перегрузку в этом случае.
Вы можете легко исправить это, изменив статический тип переменной на
IEnumerable<SomeImplementation>
, который будет работать, и теперь вы знаете, почему.IEnumerable<SomeImplementation> instances = new List<SomeImplementation>();
Вы пытались реализовать первый без дженериков, так как он должен вести себя одинаково:
public static void Method(this SomeInterface parameter) { /*...*/ }
Или, как предложил Дмитрий, путем вызова второго из следующих способов:
instances.Method<SomeImplementation>();
Но здесь вам нужно добавить <SomeImplementation>
к каждому вызову ...
Shoot
для T
, то другой метод должен звучать как ShootThemAll
или что-то подобное. IEnumerable<SomeImplementation> instances = new List<SomeImplementation>();
instances.Method(); //now this should work
instances.Method<SomeImplementation>();