Может ли «this» когда-либо иметь значение null в Java?

109

Увидел эту строку в методе класса, и моей первой реакцией было высмеять разработчика, который ее написал ... Но потом я подумал, что сначала должен убедиться, что я прав.

public void dataViewActivated(DataViewEvent e) {
    if (this != null)
        // Do some work
}

Будет ли эта строка когда-либо считаться ложной?

Брайс Фишер
источник
104
Всегда сначала высмеивайте, а потом задавайте вопросы. Легче извиниться, чем использовать прекрасную возможность разорвать кого-то в шквале серы.
Джоэл Этертон,
5
+1 за термин «шквал серы».
Марти Питт,
13
Знаете, что смешного? Это может произойти в C # из-за ошибки компилятора!
Blindy
1
@Blindy даст +1 за образец кода.
Натан Фегер,
6
ну в C # он может быть нулевым. В некоторых крайних случаях. У меня был такой же порыв: высмеять лоха, но потом я просто успокоился. Посмотрите здесь: stackoverflow.com/questions/2464097/…
Андрей Ринеа 01

Ответы:

88

Нет, не может. Если вы используетеthis , значит, вы находитесь в экземпляре, поэтому thisон не равен нулю.

JLS говорит:

При использовании в качестве основного выражения ключевое слово this обозначает значение, которое является ссылкой на объект, для которого был вызван метод экземпляра (§15.12), или на создаваемый объект.

Если вы вызвали метод из объекта, то объект существует или у вас будет NullPointerExceptionранее (или это статический метод, но тогда вы не можете использоватьthis ).


Ресурсы :

Колин Хеберт
источник
4
Я плохо разбираюсь в Java, но в C ++ thisметод экземпляра может иметь значение NULL. Поэтому я не совсем уверен, что это достаточная причина для Java.
kennytm
4
исключение нулевого указателя в чем-то вроде foo.bar()будет выброшено, когда fooбудет обнаружено null. это действительно происходит до входа в метод, но на самом деле нет метода, который можно было бы вызвать.
Claudiu
5
@KennyTM: в Java этого достаточно. Если вы используете thisключевое слово, и оно компилируется, оно не равно нулю, когда вы его наблюдаете. Но, как говорят другие, это не предотвращает NPE при попытке вызвать метод, например, но это полностью вне вашего контроля как метода, и проверка на null внутри метода ничего не изменит.
Марк Питерс,
5
@Kenny: Не обошлось и без неопределенного поведения , хотя, если вы знаете детали своей реализации, вы могли бы ее использовать.
4
Я бы не подписался под этим окончательным ответом, даже если он имеет полный смысл. У меня есть отчеты о сбоях для приложения Android, где this == null, когда метод экземпляра вызывается сразу после того, как переменная обнуляется из другого потока. Фактический вызов выполняется, даже если переменная имеет значение NULL, и происходит сбой при попытке прочитать член экземпляра :)
Адриан Креу
63

Это как спрашивать себя: «Я жив?» thisникогда не может быть нулевым

bragboy
источник
44
Я я жив ?! О боже, я больше не знаю
Клаудиу,
Вы говорите, что это this != nullбыло само собой разумеющимся. Это не так - в C ++, например, thisвполне может быть NULL, для невиртуального метода.
Ники
1
@nikie В каком-то смысле это само собой разумеющееся. Даже в C ++ любая программа, в которой это происходит, имеет неопределенное поведение. Это также может произойти с виртуальными функциями на GCC: ideone.com/W7RmU .
Йоханнес Шауб - литб,
8
@ Джон: Да. Часть пыток в том, что вы не можете это подтвердить.
@ JohannesSchaub-litb Неправда, что поведение программы на C ++ с нулевой ссылкой для этого не определено. Это определено, если вы не разыменовываете это
Rune FS
9

Нет никогда , ключевое слово this само по себе представляет текущий активный экземпляр (объект) этого класса в рамках этого класса, с помощью которого вы можете получить доступ ко всем его полям и членам (включая конструкторы), а также к видимым полям его родительского класса.

И, что более интересно, попробуйте установить его:

this = null;

Подумай об этом? Как такое возможно, разве это не будет похоже на срезку ветки, на которой вы сидите. Поскольку ключевое слово 'this' доступно в рамках класса, как только вы скажете this = null; в любом месте класса вы в основном просите JVM освободить память, назначенную этому объекту, в середине некоторой операции, которую JVM просто не может допустить, поскольку она должна безопасно вернуться обратно после завершения этой операции.

Более того, попытка this = null;приведет к ошибке компилятора. Причина довольно проста: ключевому слову в Java (или любом другом языке) никогда не может быть присвоено значение, т.е. ключевое слово никогда не может быть левым значением операции присваивания.

Других примеров не скажешь:

true = new Boolean(true);
true = false;
sactiw
источник
Хорошее объяснение, друг.
Панкадж Шарма
@PankajSharma Спасибо :)
sactiw
Я нашел это, потому что хотел посмотреть, смогу ли я его использовать this = null. Мой экземпляр находился в android, где я хотел удалить представление и установить для объекта, обрабатывающего представление, значение null. Затем я хотел использовать метод, remove()который удалял бы фактическое представление, а затем объект-обработчик стал бы бесполезным, поэтому я хотел обнулить его.
Yokich
Не уверен, что согласен с вашими утверждениями. (по крайней мере, средняя часть; часть lvalue в порядке ... хотя я почти уверен, что на самом деле есть сломанные языки, которые позволяют вам назначать, например, true = false (и даже языки, которые я бы не назвал сломанными, могут разрешить это с Отражение или подобная уловка)). В любом случае, если у меня есть объект foo, и я должен был сделать (игнорируя, что это незаконно) foo.this = null, foo все равно будет указывать на память, и поэтому JVM не будет собирать его мусором.
Foon
@Foon ну, вопрос в точности касается языка Java, более того, я не встречал ни одного языка, на котором разрешена установка this = null. То есть, если такие языки действительно существуют, то я очень сомневаюсь, что «this» в таких языках будет иметь тот же контекст и идеологию.
жертву
7

Если вы компилируете с -target 1.3или ранее, то внешний this может быть null. Или, по крайней мере, раньше ...

оборота Tom Hawtin - tackline
источник
2
Я предполагаю, что с помощью отражения мы можем установить для внешнего this значение null. может быть первоапрельской шуткой на кого - то , когда он получил исключение нулевого указателя в ссылкахOuter.this.member
irreputable
3

Нет. Чтобы вызвать метод экземпляра класса, этот экземпляр должен существовать. Экземпляр неявно передается как параметр методу, на который ссылается this. Если thisне было , nullто там бы было ни одного случая , чтобы вызвать метод.

Клаудиу
источник
3

Недостаточно того, что язык навязывает это. Виртуальной машине необходимо обеспечить его соблюдение. Если виртуальная машина не применяет его, вы можете написать компилятор, который не будет принудительно проверять значение null перед вызовом метода, написанного на Java. Коды операций для вызова метода экземпляра включают загрузку this ref в стек, см. Http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Замена этого на нулевое значение действительно приведет к тому, что тест будет ложным.

Руна FS
источник
3

В методах статического класса thisне определено, поскольку thisсвязано с экземплярами, а не с классами. Я считаю, что попытка использовать thisключевое слово в статическом контексте приведет к ошибке компилятора .

Burkestar
источник
2

Нормальный thisникогда не может быть nullв реальном Java-коде 1 , и в вашем примере используется нормальныйthis . См. Другие ответы для более подробной информации.

Квалифицированного никогда не this должно быть null, но это можно сломать. Учтите следующее:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

       public String toString() {
           return "outer is " + Outer.this;  // Qualified this!!
       }
   }
}

Когда мы хотим создать экземпляр Inner, нам нужно сделать следующее:

public static void main(String[] args) {
    Outer outer = new Outer();
    Inner inner = outer.new Inner();
    System.out.println(inner);

    outer = null;
    inner = outer.new Inner();  // FAIL ... throws an NPE
}

Результат:

outer is Outer@2a139a55
Exception in thread "main" java.lang.NullPointerException
        at Outer.main(Outer.java:19)

показывая, что наша попытка создать объект Innerсо nullссылкой на Outerнего не удалась.

Фактически, если вы придерживаетесь "чистой Java" оболочки, вы не сможете этого нарушить.

Однако у каждого Innerэкземпляра есть скрытое finalсинтетическое поле (называемое "this$0"), которое содержит ссылку на Outer. Если вы действительно коварны, можно использовать «нечистые» средства для присвоения nullполю.

  • Вы могли бы использовать Unsafeдля этого.
  • Для этого вы можете использовать собственный код (например, JNI).
  • Вы можете сделать это с помощью отражения.

В любом случае вы это делаете, конечный результат в том , что Outer.thisвыражение будет вычисляться null2 .

Короче говоря, это возможно для квалифицированного thisбыть null. Но это невозможно, если ваша программа следует правилам "чистой Java".


1. Я сбрасываю со счетов такие уловки, как «написание» байт-кодов вручную и выдача их за настоящую Java, настройка байт-кодов с помощью BCEL или подобного, или переход в машинный код и манипуляция с сохраненными регистрами. ИМО, это НЕ Java. Гипотетически такие вещи также могут произойти в результате ошибки JVM ... но я не припоминаю, чтобы каждый видел отчеты об ошибках.

2 - На самом деле JLS не говорит, каким будет поведение, и это может зависеть от реализации ... среди прочего.

Стивен С
источник
1

Когда вы вызываете метод по nullссылке, NullPointerExceptionон будет брошен из виртуальной машины Java. Это спецификация, поэтому, если ваша виртуальная машина Java строго соответствует спецификации, thisникогда не будет null.

тиа
источник
1

Если метод статический, значит, его нет this. Если метод виртуальный, он thisне может иметь значение NULL, потому что для вызова метода среда выполнения должна будет ссылаться на vtable с помощью thisуказателя. Если метод не виртуальный, то да, возможно, thisон нулевой.

C # и C ++ допускают невиртуальные методы, но в Java все нестатические методы являются виртуальными, поэтому thisникогда не будут иметь значение NULL.

Джон Хенкель
источник
0

tl; dr, «this» можно вызвать только из нестатического метода, и все мы знаем, что нестатический метод вызывается из какого-то объекта, который не может быть нулевым.

Адам
источник