tl; dr
İçin alanlar , int b = b + 1
çünkü yasadışı b
bir yasadışı ileri referanstır b
. int b = this.b + 1
Şikayet olmadan derleyen yazarak bunu gerçekten düzeltebilirsiniz .
İçin yerel değişkenler , int d = d + 1
çünkü yasadışı d
kullanımdan önce başlatılmadı. Bu, her zaman varsayılan olarak başlatılan alanlar için geçerli değildir .
Derlemeye çalışarak farkı görebilirsiniz.
int x = (x = 1) + x;
alan bildirimi ve yerel değişken bildirimi olarak. İlki başarısız olacak, ancak ikincisi anlambilimdeki farklılık nedeniyle başarılı olacaktır.
Giriş
Öncelikle, alan ve yerel değişken başlatıcıların kuralları çok farklıdır. Yani bu cevap, kuralları iki bölümde ele alacaktır.
Bu test programını aşağıdakiler boyunca kullanacağız:
public class test {
int a = a = 1;
int b = b + 1;
public static void Main(String[] args) {
int c = c = 1;
int d = d + 1;
}
}
Beyanı b
geçersizdir ve bir illegal forward reference
hata ile başarısız olur .
Beyanı d
geçersizdir ve bir variable d might not have been initialized
hata ile başarısız olur .
Bu hataların farklı olması, hataların sebeplerinin de farklı olduğunu ima etmelidir.
Alanlar
Java'daki alan başlatıcıları JLS §8.3.2 , Alanların Başlatma tarafından yönetilir .
Kapsamı bir alanın tanımlandığı §6.3 JLS beyan Kapsamı.
İlgili kurallar şunlardır:
m
Sınıf tipi C (§8.1.6) tarafından bildirilen veya miras alınan bir üyenin bildiriminin kapsamı, iç içe geçmiş tür bildirimleri de dahil olmak üzere C'nin tüm gövdesidir.
- Örnek değişkenler için başlatma ifadeleri, bildirimi daha sonra metin olarak gerçekleşse bile, sınıf tarafından bildirilen veya sınıf tarafından miras alınan herhangi bir statik değişkenin basit adını kullanabilir.
- Kullanımdan sonra bildirimleri metin olarak görünen örnek değişkenlerinin kullanımı, bu örnek değişkenleri kapsam dahilinde olsa bile bazen kısıtlanır. Durum değişkenlerine ileriye dönük referansı yöneten kesin kurallar için §8.3.2.3'e bakın.
§8.3.2.3 diyor ki:
Bir üyenin bildirimi, kullanılmadan önce metin olarak görünmelidir, yalnızca üye bir sınıf veya arabirim C'nin bir örnek (sırasıyla statik) alanıysa ve aşağıdaki koşulların tümü geçerliyse:
- Kullanım, C örneğinde (sırasıyla statik) değişken başlatıcıda veya C örneğinde (sırasıyla statik) başlatıcıda gerçekleşir.
- Kullanım, bir ödevin sol tarafında değildir.
- Kullanım basit bir isim aracılığıyladır.
- C, kullanımı kapsayan en içteki sınıf veya arabirimdir.
Bazı durumlar dışında, aslında bildirilmeden önce alanlara başvurabilirsiniz. Bu kısıtlamalar aşağıdaki gibi kodları önlemeyi amaçlamaktadır:
int j = i;
int i = j;
derlemeden. Java spesifikasyonu, "yukarıdaki kısıtlamalar, derleme zamanında döngüsel veya başka şekilde hatalı biçimlendirilmiş başlatmaları yakalamak için tasarlanmıştır" diyor.
Bu kurallar aslında neye indirgeniyor?
Kısacası, kurallar temel olarak, eğer (a) referans bir başlatıcı içindeyse, (b) referans atanmıyorsa, (c) referans a ise, o alana yapılan bir referanstan önce bir alan bildirmeniz gerektiğini söyler. basit ad (niteleyici gibi değildir this.
) ve (d) bir iç sınıftan erişilmiyor. Bu nedenle, dört koşulu karşılayan ileriye yönelik bir referans yasa dışıdır, ancak en az bir koşulda başarısız olan ileri bir referans uygundur.
int a = a = 1;
derler o (b) ihlal ettiğinden: Referans a
edilir o başvurmak için yasal yüzden, tahsis edilen a
öncesinde a
'ın tam beyanı.
int b = this.b + 1
(c) 'yi ihlal ettiği için de derler: referans this.b
basit bir isim değildir (ile nitelenir this.
). Bu garip yapı hala mükemmel bir şekilde tanımlanmıştır, çünkü this.b
sıfır değerine sahiptir.
Bu nedenle, temel olarak, başlatıcılardaki alan referansları üzerindeki kısıtlamalar int a = a + 1
başarılı bir şekilde derlenmesini engeller .
Alan beyanı olduğunu gözlemleyin int b = (b = 1) + b
edecektir başarısız nihai çünkü derlemek için b
hala yasadışı ileri referanstır.
Yerel değişkenler
Yerel değişken bildirimleri JLS §14.4 , Yerel Değişken Beyanı Beyanları tarafından yönetilir .
Kapsamı yerel bir değişkenin de tanımlandığı JLS §6.3 , beyan Kapsamı:
- Bir bloktaki yerel değişken bildiriminin kapsamı (§14.4), bildirimin göründüğü bloğun geri kalanıdır, kendi başlatıcısı ile başlar ve yerel değişken bildirim bildiriminde sağdaki diğer bildiricileri içerir.
Başlatıcıların, bildirilen değişkenin kapsamında olduğuna dikkat edin. Öyleyse neden int d = d + 1;
derlemiyor?
Bunun nedeni Java'nın kesin atama kuralından kaynaklanmaktadır ( JLS §16 ). Kesin atama, temel olarak, yerel bir değişkene her erişimin bu değişkene önceden bir atama yapması gerektiğini söyler ve Java derleyicisi, atamanın her zaman herhangi bir kullanımdan önce gerçekleştiğinden emin olmak için döngüleri ve dalları kontrol eder (bu nedenle, belirli atamanın, özel ona). Temel kural şudur:
- Yerel bir değişken veya boş nihai alanın her erişim için
x
, x
kesinlikle erişime önce atanan veya derleme zamanı hatası oluşur edilmelidir.
İçinde int d = d + 1;
, erişim d
yerel ince ince değişkenine çözümlenir, ancak d
daha önce d
erişilmediği için derleyici bir hata verir. İçinde int c = c = 1
, c = 1
önce gerçekleşir, atanır c
ve ardından c
bu atamanın sonucuna başlatılır (1'dir).
Çünkü kesin atama kuralları, yerel değişken bildirimi geldiğini hatırlatırız int d = (d = 1) + d;
olacak (başarıyla derlemek aksine saha beyanı int b = (b = 1) + b
nedeniyle,) d
kesinlikle zaman atanır nihai d
ulaşılır.
static
sınıf kapsamı değişkeninestatic int x = x + 1;
eklerseniz, aynı hatayı alır mısınız? Çünkü C # 'da statik olup olmaması bir fark yaratır.