отказ
Прежде чем продолжить, я должен сказать, что методы, описанные в этой статье, не служат никакой практической цели при программировании Java. Это как кроссворд или головоломка. Это главное тренирует ваш мозг в логическом мышлении, может развить ваши знания языка Java или даже ваши навыки мышления. Это похоже на трюк, который выполняет маг. В конце вы понимаете, что ничто не является тем, на что это похоже. Никогда не применяйте в реальной жизни такие трюки, которые вам, возможно, придется применить, чтобы решить эту проблему.
Эта проблема
Я недавно прочитал статью, в которой описан случай отладки, когда
if(trouble != null && !trouble.isEmpty()) { System.out.println(“fine here: ” + trouble); }else{ System.out.println(“not so fine here: ” + trouble); }
распечатывал
fine here: null
Фактическая ошибка заключалась в том, что строка содержала «ноль», то есть символы «n», «u», «l» и «l». Может случиться в реальной жизни, особенно когда вы объединяете строки, не проверяя недействительность переменной.
Затем я начал думать о другом подобном странном коде и ситуации отладки. Могу ли я сделать так, чтобы переменная представляла собой не только «нулевую» строку с этими символами, но и действительно нулевую? Кажется сумасшедшим? Посмотрите на код:
package com.javax0.blog.nullisnotnull; public class NullIsNotNull { public static void troubled(){ String trouble = new String("hallo"); Object z = trouble != null && !trouble.toString().isEmpty() ? trouble.toString() : ""; if (z == null) { System.out.println("z is really " + z + "?"); } } }
Будет ли это когда-либо распечатать
z is really null?
вопрос. Дело в том, что вы можете создать класс Java, содержащий открытую статическую функцию void main (), чтобы при запуске этого класса в качестве приложения Java было напечатано предложение, когда main () вызовет метод Trouble (). Другими словами: я действительно вызываю метод Trouble (), и решение не в том, что main () печатает предложение.
В этом случае переменная z не только печатается как «ноль», но и действительно равна нулю.
Советы
Решение не должно включать
- отражение
- манипулирование байтовым кодом
- вызывая JNI
- погрузчики специального класса
- Java-агент
- процессор аннотаций
Это слишком тяжелые инструменты. Вам не нужен такой арсенал для этой цели.
Подсказка № 1
Если я изменю код так, чтобы переменная z была String, она даже не скомпилировалась:
Это то, что я вижу в Eclipse
Если вас это смутило еще больше, то извините. Читать дальше!
Подсказка № 2
В языке Java String является идентификатором, а не ключевым словом. Спецификация языка Java раздел 3.9 может дать больше информации о значении этого.
Подсказка № 3
Метод toString () в классе Object имеет тип возвращаемого значения java.lang.String. Вы можете прочитать мою статью о разнице между именем, простым именем и каноническим именем класса. Это может пролить некоторый свет и увеличить количество просмотров статьи.
Подсказка № 4
Чтобы использовать класс, объявленный в том же пакете, вам не нужно импортировать этот пакет.
Решение
Решение состоит в том, чтобы создать класс с именем String в том же пакете. В этом случае компилятор будет использовать этот класс вместо java.lang.String. Тернарный оператор в коде — простой фокусник. Что-то, чтобы отвлечь ваше внимание от важного момента. Главное, что String не является java.lang.String в приведенном выше коде. Если вы все еще не можете выяснить, как создать трюковый класс, нажмите на свернутый блок исходного кода, чтобы увидеть его во всей красе:
package com.javax0.blog.nullisnotnull; class String { private java.lang.String jString; private boolean first = true; public String(java.lang.String s) { jString = s; } public boolean isEmpty() { return jString.isEmpty(); } @Override public java.lang.String toString() { if( first ){ first = false; return jString; } return null; } public static void main(java.lang.String[] args) { NullIsNotNull.troubled(); } }