Чи може "це" колись бути недійсним на Java?


109

Бачив цей рядок методом класу, і моєю першою реакцією було висміювати розробника, який його написав. Але потім, я зрозумів, що я повинен переконатися, що я маю рацію спочатку.

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

Чи буде цей рядок колись оцінюватись як хибний?


104
Завжди висміюйте спочатку, а запитання пізніше. Простіше вибачитись, ніж відвоювати золоту можливість зірвати когось у шквалі сірки.
Джоел Етертон

5
+1 за терміном "шквал сірки".
Марті Пітт

13
Ви знаєте, що смішного? Це може статися в C # через помилку компілятора!
Сліпий

1
@Blindy дасть +1 для зразка коду.
Натан Фегер

6
добре в C # це може бути нульовим. У деяких крайніх випадках. У мене був такий самий порив: висміяти присоски, але потім я просто заспокоївся. Подивіться тут: stackoverflow.com/questions/2464097 / ...
Андрій Rînea

Відповіді:


88

Ні, не може. Якщо ви використовуєтеthis , то ви знаходитесь в екземплярі, тому thisне є нульовим.

JLS говорить:

Якщо використовується як основний вираз, ключове слово позначає це значення, яке є посиланням на об'єкт, для якого викликався метод екземпляра (§15.12), або на об'єкт, який будується.

Якщо ви викликали метод від об'єкта, то об'єкт існує або у вас був би NullPointerExceptionраніше (або це статичний метод, але тоді ви не можете його використовувати this).


Ресурси:


4
Я не знаю глибоко про Java, але в C ++ thisметодом екземпляра може бути NULL. Тому я не зовсім впевнений, що це достатня причина в Java.
kennytm

4
виняток нульових покажчиків у чомусь подібному foo.bar()буде кинутий, коли fooбуде виявлено null. це трапляється до введення методу, але реальна історія полягає в тому, що немає способу спроби викликати.
Клавдіу

5
@KennyTM: цього достатньо на Java. Якщо ви використовуєте thisключове слово і воно компілюється, воно не є нульовим, коли ви його спостерігаєте. Але, як говорять інші, це не заважає NPE при спробі викликати метод, наприклад, але це повністю виходить з вашого контролю як методу, і нульова перевірка в методі нічого не змінить.
Марк Петерс

5
@Kenny: Не без невизначеної поведінки , хоча якщо ви знаєте деталі вашої реалізації, ви можете її використовувати.

4
Я б не підписався на цю остаточну відповідь, навіть якщо це має повний сенс. У мене є звіти про збої для програми Android, де це == null, коли метод екземпляра викликається відразу після того, як змінна буде ідентифікована з іншого потоку. Фактичний виклик проходить навіть у тому випадку, якщо змінна є нульовою, і вона руйнується, коли вона намагається прочитати члена екземпляра :)
Adrian Crețu

63

Це як запитати себе "Я живий?" thisніколи не може бути нульовим


44
Я я живий?! o Боже, я більше не знаю
Клавдіу,

Ви робите це звуком так, як це this != nullбуло само собою зрозумілим. Це не так - наприклад, у C ++ це thisможе бути NULLдля невіртуального методу.
Нікі

1
@nikie У певному сенсі це само собою зрозуміло. Навіть у C ++ будь-яка програма, де це відбувається, має невизначене поведінку. Це також може статися з віртуальними функціями в GCC: ideone.com/W7RmU .
Йоханнес Шауб - ліб

8
@John: Ти є. Частиною катувань є те, що ви не можете цього підтвердити.

@ JohannesSchaub-litb Неправда, що поведінка програми c ++ з нульовим відхиленням для цього не визначена. Це визначено до тих пір, поки ви цього не зведете на озброєння
Rune FS

9

Ніколи ні , ключове слово "цей" саме по собі представляє поточний живий екземпляр (об'єкт) цього класу в межах цього класу, за допомогою якого ви можете отримати доступ до всіх його полів та членів (включаючи конструктори) та видимих ​​елементів його батьківського класу.

І, що цікавіше, спробуйте встановити його:

this = null;

Подумай над цим? Як це можливо, чи не буде це як різання гілки, на якій ти сидиш. Оскільки ключове слово "це" доступне в межах класу, як тільки ви скажете це = null; в будь-якому місці класу, тоді ви в основному просите JVM звільнити пам'ять, присвоєну цьому об'єкту в середині деякої операції, яку JVM просто не може дозволити, тому що їй потрібно безпечно повернутися назад після завершення цієї операції.

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

Інші приклади ви не можете сказати:

true = new Boolean(true);
true = false;

Добре пояснення друже.
Панкай Шарма

@PankajSharma Спасибі :)
sactiw

Я знайшов це, тому що хотів побачити, чи можу я використовувати this = null. Мій екземпляр знаходився в android, де я хотів видалити подання і встановив об'єкт, що обробляє погляд, нульовим. Тоді я хотів скористатися методом, remove()який видалив би фактичний вигляд, і тоді обробник-об’єкт виявиться марним, тому я хотів його обнулити.
Йокич

Не впевнений, що я згоден з вашими претензіями. (принаймні середня частина; частина значення lvalue гарна ... хоча я впевнений, що насправді є зламані мови, які дозволяють призначити, наприклад, true = false (і навіть мови, які я б не назвав зламаними, це можуть дозволити Рефлексія чи подібна хитрість)). У будь-якому разі, якщо у мене є якийсь об'єкт foo, і я мав це робити (ігноруючи, що це незаконно) foo.this = null, foo все одно вказуватиме на пам'ять, і тому JVM не збирає сміття.
Foon

@Foon добре, питання точно говорить про мову Java, більше того, я не натрапив на будь-яку мову, де встановлення цього = null дозволено. Тобто, якщо такі мови існують, то я дуже сумніваюся, що "це" в таких мовах матиме той самий контекст та ідеологію.
sactiw

7

Якщо ви компілюєте з -target 1.3чи раніше, то зовнішній this може бути null. Або, принаймні, раніше ...


2
Я думаю, що через рефлексію ми можемо встановити нульове значення зовнішнього. може бути Outer.this.member
жартовним

3

Ні. Щоб викликати метод екземпляра класу, екземпляр повинен існувати. Екземпляр неявно передається як параметр методу, на який посилається this. Якщо thisне було , nullто там би було ні одного випадку , щоб викликати метод.


3

Мало того, що мова це виконує. ВМ потрібно її застосувати. Якщо VM не застосовує його, ви можете написати компілятор, який не примушує перевірити нуль перед викликом методу, написаного на Java. Опкоди виклику методу екземпляра включають завантаження цього посилання на стек, див .: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Замінивши це нульовим посиланням, справді це призведе до помилки тесту


3

У методах статичного класу thisне визначено, оскільки thisасоціюється з екземплярами, а не класами. Я вважаю, що це призведе до помилки компілятора для спроби використання thisключового слова в статичному контексті.


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 або подібних, або перестрибувати в нативний код і перебирати зі збереженими регістрами. IMO, це НЕ Java. Гіпотетично подібні речі можуть траплятися і внаслідок помилки JVM ... але я не пригадую кожного звіту про помилки.

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


1

Коли ви посилаєтесь на метод nullпосилання, NullPointerExceptionвикид буде передано з Java VM. Це за специфікацією, тому якщо ваша Java VM суворо відповідає специфікації, thisніколи не буде null.


1

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

C # і C ++ дозволяють невіртуючі методи, але на Java всі нестатичні методи є віртуальними, тому thisніколи не будуть нульовими.


0

tl; dr, "це" можна викликати лише з нестатичного методу, і всі ми знаємо, що нестатичний метод викликається від якогось об'єкта, який не може бути нульовим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.