Java'da "bu" hiç boş olabilir mi?


109

Bu satırı bir sınıf yönteminde gördüm ve ilk tepkim onu ​​yazan geliştiriciyle alay etmek oldu .. Ama sonra, önce haklı olduğumdan emin olmam gerektiğini düşündüm.

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

Bu satır hiç yanlış olarak değerlendirilecek mi?


104
Her zaman önce alay edin ve sonra sorgulayın. Özür dilemek, bir kükürt telaşıyla birini alt üst etmek için altın bir fırsatı yeniden yakalamaktan daha kolaydır.
Joel Etherton

5
"Kükürt telaşı" terimi için +1.
Marty Pitt

13
Komik olan ne biliyor musun? Bu, bir derleyici hatası nedeniyle C # 'da olabilir!
Blindy

1
@Blindy, kod örneği için +1 verecektir.
Nathan Feger

6
iyi C # 'da boş olabilir. Bazı uç durumlarda. Aynı dürtüye sahiptim: enayi ile alay et ama sonra sakinleştim. Şuraya bir göz atın: stackoverflow.com/questions/2464097/…
Andrei Rînea

Yanıtlar:


88

Hayır yapamaz. Eğer kullanıyorsanız this, o zaman örnektesiniz yani thisboş değil.

JLS diyor ki:

Birincil ifade olarak kullanıldığında, this anahtar sözcüğü örnek yönteminin çağrıldığı nesneye (§15.12) veya inşa edilmekte olan nesneye bir başvuru olan bir değeri belirtir.

Bir nesneden bir yöntemi çağırdıysanız, o zaman nesne vardır veya bir öncekine sahip olursunuz NullPointerException(veya bu statik bir yöntemdir ancak o zaman thisiçinde kullanamazsınız ).


Kaynaklar:


4
Java hakkında derinlemesine bilgim yok, ancak C ++ 'da thisbir örnek yöntemin NULL olabilir. Bu yüzden Java'da bunun yeterli bir neden olduğuna pek ikna olmadım.
kennytm

4
olduğu keşfedildiğinde foo.bar()fırlatılacak gibi bir şeydeki boş işaretçi istisnası . yönteme girmeden önce gerçekleşir, ancak gerçek hikaye, arama girişiminde bulunmanın bir yönteminin olmamasıdır. foonull
Claudiu

5
@KennyTM: Java'da yeterlidir. thisAnahtar kelimeyi kullanıyorsanız ve derlerse, onu gözlemlediğinizde boş değildir. Ancak diğerlerinin dediği gibi, yöntemi çağırmaya çalışırken bir NPE'yi engellemiyor, örneğin. Ancak bu, bir yöntem olarak tamamen sizin kontrolünüz dışında ve yöntem içindeki bir boş kontrol hiçbir şeyi değiştirmeyecek.
Mark Peters

5
@Kenny: Tanımlanmamış davranışlar olmadan olmaz , uygulamanızın ayrıntılarını biliyorsanız, onu kullanabilirsiniz.

4
Tamamen mantıklı olsa bile, bu kesin yanıta katılmam. Değişkenin başka bir iş parçacığından sıfırlanmasından hemen sonra bir örnek yöntemi çağrıldığında this == null olan bir Android uygulaması için kilitlenme raporlarım var. Değişken boş olsa bile gerçek çağrı devam eder ve bir örnek üyesini okumaya çalıştığında çöker :)
Adrian Crețu

63

Kendinize "Yaşıyor muyum?" Diye sormak gibi thisasla boş olamaz


44
ben hayatta ?! aman tanrım artık bilmiyorum
Claudiu

Bunu apaçıkmış gibi gösteriyorsun this != null. C ++ 'da değildir, örneğin, sanal olmayan bir yöntem için thispekala olabilir NULL.
Niki

1
@nikie Bir anlamda, apaçık ortada. C ++ 'da bile, bunun gerçekleştiği herhangi bir programın tanımsız davranışı vardır. GCC'deki sanal işlevler için de olabilir: ideone.com/W7RmU .
Johannes Schaub -

8
@John: Öylesin. İşkencenin bir parçası da bunu onaylayamamaktır.

@ JohannesSchaub-litb Bunun için boş ref olan bir c ++ programının davranışının tanımsız olduğu doğru değildir. Buna referansta bulunmadığınız sürece tanımlanır
Rune FS

9

Hiçbir zaman , 'bu' anahtar kelimesinin kendisi, sınıfın kapsamındaki, tüm alanlarına ve üyelerine (yapıcılar dahil) ve üst sınıfının görünür olanlarına erişebileceğiniz o sınıfın mevcut canlı örneğini (nesnesini) temsil eder.

Daha da ilginci, ayarlamayı deneyin:

this = null;

Bunu düşün? Nasıl mümkün olabilir ki, oturduğunuz dalı kesmek gibi olmayacak mı? 'This' anahtar kelimesi sınıf kapsamında mevcut olduğundan, bu nedenle bu = null dediğiniz anda; sınıfın herhangi bir yerinde JVM'den, JVM'nin bu işlemi tamamladıktan sonra güvenli bir şekilde geri dönmesi gerektiğinden olmasına izin veremeyeceği bazı işlemlerin ortasında o nesneye atanan belleği boşaltmasını istersiniz.

Ayrıca, denemek this = null;derleyici hatasına neden olacaktır. Sebep oldukça basittir, Java'daki (veya herhangi bir dildeki) bir anahtar kelimeye asla bir değer atanamaz, yani bir anahtar kelime asla bir atama işleminin sol değeri olamaz.

Diğer örnekler, şunu söyleyemezsiniz:

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

İyi açıklama arkadaşım.
Pankaj Sharma

@PankajSharma Thanks :)
sactiw

Bunu buldum çünkü kullanıp kullanamayacağımı görmek istedim this = null. Örneğim, bir görünümü kaldırmak ve görünümü işleyen nesneyi null olarak ayarlamak istediğim yerde androiddeydi. Sonra remove()gerçek görünümü kaldıracak bir yöntem kullanmak istedim ve sonra işleyici nesnesi işe yaramaz hale gelecek, bu yüzden onu sıfırlamak istedim.
Yokich

İddialarına katılıyorum emin değilim. (en azından orta kısım; lvalue kısmı iyidir ... gerçi aslında örneğin true = false atamanıza izin veren bozuk diller olduğundan oldukça eminim (ve kırık demediğim diller bile buna izin verebilir Düşünme veya benzeri hile)). Her neyse, eğer foo nesnem varsa ve yapmam (yasadışı olduğunu görmezden gelerek) foo.this = null, foo yine de belleğe işaret eder ve böylece JVM onu çöp toplamaz.
Foon

@Foon, soru tam olarak Java dilinden bahsediyor, üstelik this = null ayarına izin verilen herhangi bir dile rastlamadım. Yani, eğer bu tür diller varsa, o zaman bu tür dillerdeki "bu" nun aynı bağlam ve ideolojiye sahip olacağından şüpheliyim.
sactiw

7

İle -target 1.3veya daha önce derlerseniz, bir dış this olabilir null. Ya da en azından eskiden ...


2
Sanırım yansıma yoluyla dıştaki bunu sıfıra ayarlayabiliriz. Referanslamada boş işaretçi istisnası olan birine 1 Nisan şakası olabilirOuter.this.member
reddedilemez

3

Hayır. Bir sınıfın bir örneğinin yöntemini çağırmak için, örneğin var olması gerekir. Örnek, başvuruda bulunulan yönteme bir parametre olarak örtük olarak iletilir this. Eğer thisedildi null, sonra bir yöntemini çağırmak için örnek yoktur olurdu.


3

Dilin onu zorlaması yeterli değil. Sanal makinenin bunu uygulaması gerekiyor. Sanal makine bunu zorlamadıkça, Java ile yazılmış yöntemi çağırmadan önce boş kontrolü zorlamayan bir derleyici yazabilirsiniz. Bir örnek yöntemi çağrısı için işlem kodları, bu referansın yığına yüklenmesini içerir, bkz: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Bunu boş bir referansla değiştirmek gerçekten testin yanlış olmasına neden olur


3

Statik sınıf yöntemlerinde, sınıflarla değil örneklerle ilişkili thisolduğundan tanımlanmamıştır this. thisAnahtar kelimeyi statik bağlamda kullanmayı denemenin bir derleyici hatası vereceğine inanıyorum .


2

Bir normal thisasla nullgerçek Java kodu 1'de olamaz ve örneğiniz bir normal this. Daha fazla ayrıntı için diğer cevaplara bakın.

Bir nitelikli this gerektiğini asla null, ama bu kırmak mümkündür. Aşağıdakileri göz önünde bulundur:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

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

Bir örnek oluşturmak istediğimizde Inner, bunu yapmamız gerekir:

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
}

Çıktı:

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

çabamız bir oluşturmak için olduğunu gösteren Innerbir ile nullonun referans Outerbaşarısız oldu.

Aslında, "Saf Java" zarfının içinde kalırsanız, bunu kıramazsınız.

Bununla birlikte, her bir Innerörnek, bir gizli sahiptir final(denilen sentetik alan "this$0"referans içerir) Outer. Eğer gerçekten zor iseniz null, alana atamak için "saf olmayan" araçlarını kullanmak mümkündür .

  • Bunu Unsafeyapmak için kullanabilirsin .
  • Bunu yapmak için yerel kodu (örneğin JNI) kullanabilirsiniz.
  • Bunu yansıma kullanarak yapabilirsiniz.

Her iki şekilde de yaparsanız, sonuç, Outer.thisifadenin null2 olarak değerlendirilmesidir .

Kısacası nitelikli olmak mümkündür . Ancak programınızın "Saf Java" kurallarına uyması imkansızdır .thisnull


1 - Bayt kodlarını elle "yazmak" ve bunları gerçek Java olarak aktarmak, BCEL veya benzerini kullanarak bayt kodlarını değiştirmek veya yerel koda atlamak ve kaydedilen kayıtlarla uğraşmak gibi hilelere önem vermem. IMO, bu Java DEĞİLDİR. Varsayımsal olarak, bu tür şeyler bir JVM hatasının bir sonucu olarak da olabilir ... ama gördüğüm her hata raporunu hatırlamıyorum.

2 - Aslında, JLS davranışın ne olacağını söylemiyor ve diğer şeylerin yanı sıra uygulamaya bağlı olabilir.


1

Üzerinde bir yöntemi çağırmak zaman nullreferans, NullPointerExceptionJava VM atılacaktır. Bu, spesifikasyona göredir, bu nedenle Java VM'niz spesifikasyona tam olarak uyuyorsa, thisasla olmayacaktır null.


1

Yöntem statikse, o zaman yoktur this. Yöntem sanal ise, thisbu durumda boş olamaz, çünkü yöntemi çağırmak için çalışma zamanının thisişaretçiyi kullanarak vtable'a başvurması gerekir . Yöntem sanal değilse , evet, bu thisboş olabilir.

C # ve C ++ sanal olmayan yöntemlere izin verir, ancak Java'da tüm statik olmayan yöntemler sanaldır, bu nedenle thishiçbir zaman boş olmayacaktır.


0

tl; dr, "this" yalnızca statik olmayan bir yöntemden çağrılabilir ve hepimiz, statik olmayan bir yöntemin boş olamayacak bir tür nesneden çağrıldığını biliyoruz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.