Статьи

Когда нулевая проверка с треском проваливается

отказ

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

Это то, что я вижу в 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();
    }
}