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, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
На самом деле VS2008 оптимизирует это к x+x:
01391000 push ecx
int x = 0;
scanf("%d", &x);
01391001 lea eax,[esp]
01391004 push eax
01391005 push offset string "%d" (13920F4h)
0139100A mov dword ptr [esp+8],0
01391012 call dword ptr [__imp__scanf (13920A4h)]
int y = x * 2;
01391018 mov ecx,dword ptr [esp+8]
0139101C lea edx,[ecx+ecx]
В сборке x64 это еще более явно и использование:
int y = x * 2;
000000013FB9101E mov edx,dword ptr [x]
printf("%d", y);
000000013FB91022 lea rcx,[string "%d" (13FB921B0h)]
000000013FB91029 add edx,edx
Это - желание, настройки оптимизации на 'Максимизируют скорость' (/O2)
Эта статья от Raymond Chen могла быть интересной:
, Когда x/2 отличающийся от x>> 1? : http://blogs.msdn.com/oldnewthing/archive/2005/05/27/422551.aspx
Заключение в кавычки Raymond:
, Конечно, компилятор является бесплатным распознать это и переписать Ваше умножение или операцию сдвига. На самом деле это, очень вероятно, сделает это, потому что x+x более легко pairable, чем умножение или сдвиг. Ваш сдвиг или multiply-two, вероятно, будут переписанными как что-то ближе к добавлению eax, eax инструкция.
[...]
, Даже если Вы предполагаете, что заливки сдвига со знаковым битом, результатом сдвига и деления отличаются, если x отрицателен.
(-1) / 2 в‰Ў 0
(-1)>> 1 в‰Ў-1
[...]
мораль истории должна записать то, что Вы имеете в виду. Если Вы хотите разделиться на два, то запишите "/2", не">> 1".
Мы можем только предположить, что мудро сказать компилятор, что Вы хотите, не, что Вы хотите, чтобы он сделал: компилятор лучше, чем человек при оптимизации мелкомасштабный код (спасибо за Daemin для указания на этот тонкий момент): Если Вы действительно хотите оптимизацию, используйте профилировщика и изучите эффективность Ваших алгоритмов.
VS 2008 оптимизированная шахта к x < < 1.
x = x * 2;
004013E7 mov eax,dword ptr [x]
004013EA shl eax,1
004013EC mov dword ptr [x],eax
РЕДАКТИРОВАНИЕ: Это использовало конфигурацию "Отладки" значения по умолчанию VS с отключенной оптимизацией (/Передозировка). Используя любой из переключателей оптимизации (/O1,/O2 (VS "Розничная продажа"), или Вол/) результаты в добавление сам кодируют отправленного Rob. Кроме того, просто в придачу я проверил x = x << 1
, действительно рассматривается тот же путь как x = x * 2
компилятором статьи и в Передозировке / и в Воле/. Так, таким образом, версия 15.00.30729.01 cl.exe для обработок x86 * 2
и << 1
тождественно и я ожидаю, что почти все другие недавние компиляторы делают то же.
Не, если x является плаванием, он не будет.
Да. Они также оптимизируют другие подобные операции, такие как умножение на неполномочия два, который может быть переписан как суммы некоторых сдвигов. Они будут также оптимизировать подразделения полномочиями 2 в сдвиги вправо, но остерегаться этого при работе с целыми числами со знаком, эти две операции отличаются! Компилятор должен испустить некоторые дополнительные инструкции по битовому жонглированию удостовериться, что результатами является то же для положительных и отрицательных чисел, но это еще быстрее, чем выполнение подразделения. Это также так же оптимизирует модули полномочиями 2.
Ответ, "если это быстрее" (или меньше). Это зависит от целевой архитектуры в большой степени, а также модели использования регистра для данного компилятора. В целом ответ "да, всегда", поскольку это - очень простая локальная оптимизация для реализации и обычно является достойной победой.
Это - только запуск того, что могут сделать оптимизаторы. Для наблюдения, что делает компилятор ищите переключатель, который заставляет его испускать ассемблерный источник. Для Цифровых компиляторов Марса выходной ассемблер может быть исследован с инструментом OBJ2ASM. Если Вы хотите изучить, как Ваш компилятор работает, смотрение на ассемблерный вывод может быть очень освещающим.
Я уверен, что они все делают подобную оптимизацию, но интересно, релевантны ли они все еще. Процессоры прежних модификаций сделали умножение путем смещения и добавления, который мог взять много циклов для завершения. Современные процессоры, с другой стороны, имеют ряд многорегистровых циклических сдвиговых устройств, которые могут сделать все необходимые сдвиги и дополнения одновременно в одном такте или меньше. Кто-либо на самом деле сравнил, помогает ли эта оптимизация действительно?
Если что-то не будет определено в стандарте языков, Вы никогда не будете получать гарантируемый ответ на такой вопрос. Когда в сомнении выложили Ваш компилятор, собирают код и проверку. Это будет единственным способом действительно знать.
@Ferruccio Барлетта
Это - хороший вопрос. Я пошел, Гугля, чтобы попытаться найти ответ.
я не мог найти ответы для процессоров Intel непосредственно, но этот , страница имеет кого-то, кто попробовал к вещам времени. Это показывает сдвиги, чтобы быть более двух раз с такой скоростью, как реклама и умножается. Сдвиги разряда так просты (где умножение могло быть сдвигом и дополнением), что это имеет смысл.
Таким образом я Погугленный AMD, и найденный старым руководством по оптимизации для Athlon с 2002, который перечисляет, который перечисляет самые быстрые способы умножить числа на константы между 2 и 32. Интересно, это зависит от числа. Некоторые - реклама, некоторые сдвиги. Это находится на страница 122 .
руководство для , Athlon 64 показывает то же самое (страница приблизительно 164). Это говорит, умножается, 3 (в 32-разрядном) или 4 (в 64-разрядном) операции цикла, где сдвиги равняются 1, и добавляет, 2.
кажется, что это все еще полезно как оптимизация.
цикл Игнорирования рассчитывает, хотя, этот вид метода препятствовал бы тому, чтобы Вы связали модули выполнения умножения (возможно), поэтому при выполнении большого умножения в жестком цикле, где некоторые константы использования и некоторые не делают дополнительная комната планирования могла бы быть полезной.
, Но это - предположение.
Это зависит, на каком компиляторе Вы имеете. Visual C++, например, известно плох в оптимизации. При редактировании сообщения для высказывания, какой компилятор Вы используете, было бы легче ответить.