отказ
Прежде чем продолжить, я должен сказать, что методы, описанные в этой статье, не служат никакой практической цели при программировании 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();
}
}