Другое событие NullPointerException
возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals
для гарантированного непустого объекта.
Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null
.
Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Я получил рабочий пример!
Основная идея получена из вики, но с некоторыми изменениями для C #. Статья в вики демонстрирует это для статического поля C ++, похоже, что C # всегда тщательно компилирует запросы к статическим полям ... и я приведу пример с нестатическим полем:
Если вы запустите этот пример в Release ] и без отладчика (т.е. используя Ctrl + F5), то строка while (test.foo! = 255)
будет оптимизирована до 'while (true)', и эта программа никогда возвращается.
Но после добавления ключевого слова volatile
вы всегда получаете «ОК».
class Test
{
/*volatile*/ int foo;
static void Main()
{
var test = new Test();
new Thread(delegate() { Thread.Sleep(500); test.foo = 255; }).Start();
while (test.foo != 255) ;
Console.WriteLine("OK");
}
}
Да, это аппаратно-зависимо (Вы вряд ли будете видеть проблему без нескольких процессоров), но это является также зависящим от реализации. Спецификации модели памяти в спецификации CLR разрешают вещи, которые реализацию Microsoft CLR не обязательно делают. Лучшая документация, которую я видел на энергозависимом ключевом слове, это сообщение в блоге Joe Duffy . Обратите внимание, что он говорит, что документация MSDN является "очень вводящей в заблуждение".
Это не действительно вопрос случая отказа, когда 'энергозависимое' ключевое слово не определяется, больше что ошибка могла произойти, когда это не было определено. Обычно Вы собираетесь знать когда дело обстоит так лучше, чем компилятор!
самый легкий образ мыслей об этом был бы то, что компилятор, если это хотело, мог бы встроить определенные значения. Путем маркировки значения как энергозависимое, Вы говорите себе и компилятору, что значение может на самом деле измениться (даже если компилятор не думает так). Это означает, что компилятор не должен встраивать значения, сохранить кэш или считать значение рано (в попытке оптимизировать).
Это поведение не является действительно тем же ключевым словом как в C++.
MSDN имеет краткое описание здесь . Вот, возможно, больше подробно сообщение на предметах Энергозависимость, Атомарность и Взаимная блокировка
Трудно продемонстрировать в C#, поскольку код абстрагирован виртуальной машиной, таким образом на одной реализации этой машины это работает правильно без энергозависимого, в то время как это могло бы перестать работать на другом.
Википедия имеет хороший пример, как продемонстрировать его в C, все же.
то же самое могло произойти в C#, если JIT-компилятор решает, что значение переменной не может измениться так или иначе и таким образом создает машинный код, который даже не проверяет его больше. Если бы теперь другой поток изменял значение, Ваш первый поток мог бы все еще быть пойман в цикле.
Другим примером является Активное ожидание.
Снова, это могло произойти с C# также, но он сильно зависит от виртуальной машины и от JIT-компилятора (или интерпретатор, если он не имеет никакого JIT... в теории, я думаю, что MS всегда использует JIT-компилятор и также Моно использование один; но Вы могли бы быть в состоянии отключить его вручную).