Может ли это когда-либо быть нулевым в Java?
Увидел эту строчку в методе класса, и моя первая реакция заключалась в том, чтобы высмеять разработчика, который ее написал. Но потом я решил, что должен убедиться, что был прав первым.
public void dataViewActivated(DataViewEvent e) {
if (this != null)
// Do some work
}
Будет ли эта строка когда-либо оценена как ложная?
10 ответов
Нет, не может. Если вы используете this
тогда вы в инстанции так this
не нуль
JLS говорит:
При использовании в качестве основного выражения ключевое слово this обозначает значение, которое является ссылкой на объект, для которого был вызван метод экземпляра (§15.12), или на конструируемый объект.
Если вы вызвали метод из объекта, то объект существует, или у вас будет NullPointerException
до (или это статический метод, но тогда вы не можете использовать this
в этом).
Ресурсы:
- JLS -
this
ключевое слово
Это все равно что спросить себя: "Я жив?" this
никогда не может быть нулевым
Нет никогда, ключевое слово "this" само по себе представляет текущий живой экземпляр (объект) этого класса в области видимости этого класса, с помощью которого вы можете получить доступ ко всем его полям и членам (включая конструкторы) и видимым из его родительского класса.
И, что более интересно, попробуйте установить его:
this = null;
Думаю об этом? Как это может быть возможно, не будет ли это как срезать ветку, на которой вы сидите. Поскольку ключевое слово "this" доступно в рамках класса, то, как только вы говорите, this = null; тогда в любом месте класса вы в основном просите JVM освободить память, выделенную этому объекту, в середине какой-то операции, которую JVM просто не может допустить, поскольку она должна безопасно вернуться после завершения этой операции.
Более того, пытаясь this = null;
приведет к ошибке компилятора. Причина довольно проста: ключевому слову в Java (или любом другом языке) никогда не может быть присвоено значение, т.е. ключевое слово никогда не может быть левым значением операции присваивания.
Другие примеры, вы не можете сказать:
true = new Boolean(true);
true = false;
Если вы компилируете с -target 1.3
или раньше, то внешний this
может быть null
, Или, по крайней мере, раньше...
Нет. Чтобы вызвать метод экземпляра класса, экземпляр должен существовать. Экземпляр неявно передается в качестве параметра методу, на который ссылается this
, Если this
было null
тогда не было бы экземпляра для вызова метода.
Нормальный 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
выражение будет оценивать null
2
Короче говоря, это возможно для квалифицированного this
быть null
, Но это невозможно, если ваша программа следует правилам "Чистой Java".
1 - Я не принимаю во внимание такие хитрости, как "написание" байт-кодов вручную и выдавание их за реальную Java, настройка байт-кодов с использованием BCEL или аналогичных, или переход в нативный код и использование сохраненных регистров. ИМО, это НЕ ЯВА. Гипотетически, такие вещи могут также произойти в результате ошибки JVM... но я не помню, чтобы каждый видел сообщения об ошибках.
2 - На самом деле, JLS не говорит, каково будет поведение, и это может зависеть от реализации... среди прочего.
В статических методах класса, this
не определено с this
связано с экземплярами, а не классами. Я считаю, что это даст ошибку компилятора, чтобы попытаться использовать this
Ключевое слово в статическом контексте.
Недостаточно того, что язык усиливает это. ВМ должна обеспечить его выполнение. Если виртуальная машина не предписывает это, вы можете написать компилятор, который не применяет нулевую проверку перед вызовом метода, написанного на Java. Коды операций для вызова метода экземпляра включают загрузку этой ссылки в стек, см. http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html. Подстановка этого значения для нулевого ref действительно приведет к тому, что тест будет ложным
Если метод статический, то нет никаких this
. Если метод виртуальный, тоthis
не может быть нулевым, потому что для вызова метода среда выполнения должна будет ссылаться на vtable с помощью this
указатель. Если метод не виртуальный, то да, возможно, чтоthis
нулевой.
C# и C++ допускают использование не виртуальных методов, но в Java все нестатические методы являются виртуальными, поэтому this
никогда не будет нулевым.
Когда вы вызываете метод на null
ссылка, NullPointerException
будет выброшен с Java VM. Это по спецификации, поэтому, если ваша виртуальная машина Java строго соответствует спецификации, this
никогда не будет null
,
tl;dr, "this" может быть вызван только из нестатического метода, и мы все знаем, что нестатический метод вызывается из некоторого объекта, который не может быть нулевым.