Statik değişkenler ne zaman başlatılır?


88

Statik değişkenlerin varsayılan değerlerine ne zaman başlatıldığını merak ediyorum. Bir sınıf yüklendiğinde, statik değişkenlerin oluşturulduğu (ayrıldığı), ardından bildirimlerdeki statik başlatıcıların ve başlatmaların çalıştırıldığı doğru mu? Varsayılan değerler hangi noktada verilmektedir? Bu ileri referans sorununa yol açar.

Ayrıca bunu, statik alanlar neden zamanında başlatılmıyor? ve özellikle Kevin Brock'un aynı sitede verdiği cevap. 3. noktayı anlayamıyorum.


2
Lütfen sorunuzu atıfta bulunduğunuz alıntıyı içerecek şekilde düzenleyin.
Oliver Charlesworth

1
Java dil özelliğini okudunuz mu? Kasıtlı olarak oldukça okunabilir bir belgedir. Bunu okuduysanız, neler olduğunu anlayabilirsiniz. Değilse, en azından daha spesifik bir soru sorabilirsiniz ...
Maarten Bodewes

Bu Soru-Cevap bölümünün stackoverflow.com/questions/3499214 adresinin kopyası olduğunu düşünüyorum .
Stephen C

Yanıtlar:


72

Gönderen Bkz Java Statik Değişken Yöntemleri :

  • Nesneye (örneğe) değil sınıfa ait bir değişkendir.
  • Statik değişkenler, yürütmenin başlangıcında yalnızca bir kez başlatılır. Bu değişkenler, herhangi bir durum değişkeninin başlatılmasından önce ilk olarak başlatılacaktır.
  • Sınıfın tüm örnekleri tarafından paylaşılacak tek bir kopya
  • Statik bir değişkene doğrudan sınıf adıyla erişilebilir ve herhangi bir nesneye ihtiyaç duymaz.

Örnek ve sınıf (statik) değişkenleri, kasıtlı olarak başlatmayı başaramazsanız, standart varsayılan değerlere otomatik olarak başlatılır. Yerel değişkenler otomatik olarak başlatılmasa da, yerel bir değişkeni başlatamayan veya kullanılmadan önce o yerel değişkene bir değer atayan bir programı derleyemezsiniz.

Derleyicinin aslında yaptığı şey, tüm statik değişken başlatıcıları ve kodun tüm statik başlatıcı bloklarını, sınıf bildiriminde göründükleri sırayla birleştiren tek bir sınıf başlatma yordamını dahili olarak üretmektir. Bu tek başlatma prosedürü, sınıf ilk yüklendiğinde yalnızca bir kez otomatik olarak çalıştırılır.

İç sınıflar durumunda, statik alanlara sahip olamazlar

Bir iç sınıfı açık veya üstü örtülü beyan edilmeyen bir iç içe sınıftır static.

...

İç sınıflar, statik başlatıcıları (§8.7) veya üye arabirimleri bildiremez ...

İç sınıflar, sabit değişkenler olmadıkça statik üyeler bildiremez ...

Bkz. JLS 8.1.3 İç Sınıflar ve Kapsayıcı Eşgörünümler

finalJava'daki alanlar, bildirim yerlerinden ayrı olarak başlatılabilir ancak bu static finalalanlara uygulanamaz . Aşağıdaki örneğe bakın.

final class Demo
{
    private final int x;
    private static final int z;  //must be initialized here.

    static 
    {
        z = 10;  //It can be initialized here.
    }

    public Demo(int x)
    {
        this.x=x;  //This is possible.
        //z=15; compiler-error - can not assign a value to a final variable z
    }
}

Bunun nedeni , örnek değişkenlerde olduğu gibi türün her bir örneğiyle ilişkili bir tane yerine türle ilişkili değişkenlerin yalnızca bir kopyasının olmasıdır ve yapıcı içinde türü staticbaşlatmaya çalışırsak, tür alanını yeniden başlatmaya çalışır. çünkü yapıcı, statik alanlarda oluşmaması gereken sınıfın her bir örneğinde çalıştırılır .zstatic finalstatic finalzfinal


5
In case of static inner classes, they can not have static fieldsbir yazım hatası gibi görünüyor. İç sınıflar statik değildir.
Daniel Lubarov

Ancak yerine kullanmalısınız
Suraj Jain

Bir JVM'yi başlattığınızda ve bir sınıfı ilk kez yüklediğinizde (bu, sınıfa herhangi bir şekilde ilk başvurulduğunda sınıf yükleyici tarafından yapılır) herhangi bir statik blok veya alan JVM'ye 'yüklenir' ve erişilebilir hale gelir.
nhoxbypass

1
Ne yazık ki bu cevap, statiğin ne zaman başlatıldığına dair bazı gerçeklere dayalı yanlışlıkları içermektedir. Lütfen stackoverflow.com/a/3499322/139985 adresine bakın .
Stephen C

15

Görmek:

Özellikle sonuncusu, statik değişkenlerin ne zaman başlatıldığını ve hangi sırayla ( derleme zamanı sabitleri olan sınıf değişkenlerinin ve arayüz alanlarının ilk olarak başlatıldığına dair uyarı ile) ayrıntılı başlatma adımları sağlar final.

3. nokta hakkındaki özel sorunuzun ne olduğundan emin değilim (iç içe olanı kastettiğinizi varsayarak?). Ayrıntılı sıra, bunun özyinelemeli bir başlatma isteği olacağını ve böylece başlatmaya devam edeceğini belirtir.


12

Statik alanlar, sınıf sınıf yükleyici tarafından yüklendiğinde başlatılır. Şu anda varsayılan değerler atanır. Bu, kaynak kodda göründükleri sırayla yapılır.


10

Başlatma sırası şöyledir:

  1. Statik başlatma blokları
  2. Örnek başlatma blokları
  3. İnşaatçılar

Sürecin ayrıntıları JVM spesifikasyon belgesinde açıklanmıştır .


6

statik değişken

  • Nesneye (örneğe) değil sınıfa ait bir değişkendir.
  • Statik değişkenler, yürütmenin başlangıcında yalnızca bir kez başlatılır (Sınıf yükleyici sınıfı ilk kez yüklediğinde).
  • Bu değişkenler, herhangi bir durum değişkeninin başlatılmasından önce ilk olarak başlatılacaktır.
  • Sınıfın tüm örnekleri tarafından paylaşılacak tek bir kopya
  • Statik bir değişkene doğrudan sınıf adı ile erişilebilir ve herhangi bir nesneye ihtiyaç duymaz.

4

Diğer sorudaki kodla başlayarak:

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

Bu sınıfa yapılan bir referans başlatmaya başlayacaktır. İlk olarak, sınıf başlatılmış olarak işaretlenecektir. Ardından, ilk statik alan yeni bir MyClass () örneği ile başlatılacaktır. MyClass'ın hemen boş bir MyClass örneğine referans verildiğini unutmayın . Boşluk oradadır, ancak tüm değerler boştur. Yapıcı artık çalıştırılır ve objnull olan yazdırır .

Şimdi sınıfı ilklendirmeye geri dönelim: objyeni bir gerçek nesneye referans yapıldı ve işimiz bitti.

Bu, aşağıdaki gibi bir ifadeyle ayarlandıysa: MyClass mc = new MyClass();yeni bir Sınıfım örneği için alan yeniden tahsis edilir (ve referans yerleştirilir mc). Yapıcı tekrar çalıştırılır ve tekrar yazdırılır obj, bu artık boş değildir.

Buradaki gerçek numara, kullandığınız zaman new, olduğu gibi WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weiihemen bir miktar boş belleğe referans verilmesidir. JVM daha sonra değerleri başlatmaya ve kurucuyu çalıştırmaya devam edecektir. Ancak, bunu weii yapmadan önce bir şekilde başvurursanız - başka bir iş parçacığından başvurarak veya örneğin sınıf başlatmadan başvurarak - boş değerlerle dolu bir sınıf örneğine bakarsınız.


1
Bir sınıf, başlatma tamamlanana kadar başlatılmış olarak işaretlenmez - aksi takdirde yapmak mantıklı olmaz. Başlatıldı olarak işaretleme, neredeyse atılan son adımdır. JLS 12.4.2'ye bakınız .
Dave Newton

@DaveNewton: Bir şey sınıfa başvurduğunda ve onu başlatmaya başladığında, diğer tüm referanslar sınıfı başlatılmış olarak değerlendirecektir. Başlatmaya çalışmayacaklar ve başlatılmasını beklemeyecekler. Bu nedenle, bir programın başlangıcından itibaren boş görünmeyen alanlar aslında bir süre boş olabilir. Bunu anlamamak, tüm karışıklığa neden olan şeydir. Sanırım en basit şekilde, başlatılmamış bir sınıfın ilk referansta başlatılmış olarak "işaretlendiğini", diğer tüm referansların bunu intialized olarak ele aldığını ve bunun nedeni bu olduğunu düşünüyorum.
RalphChapin

Önceki yoruma bir düzeltme: Dave Newton'un JLS 12.4.2'sinde açıklandığı gibi, sınıf başlatılırken kilitlenir . Diğer konu olacak sınıfı başlatılması için bekleyin. Ancak bu, hepsi tek bir iş parçacığında gerçekleşen bu durumu etkilemez.
RalphChapin

4

Statik değişken, aşağıdaki üç şekilde tanıtılabilir, aşağıdaki gibi istediğiniz birini seçin

  1. bildirim anında bunu başlatabilirsiniz
  2. veya statik blok yaparak yapabilirsiniz, örneğin:

    static {
            // whatever code is needed for initialization goes here
        }
    
  3. Statik bloklara bir alternatif var - özel bir statik yöntem yazabilirsiniz

    class name {
        public static varType myVar = initializeVar();
    
        private static varType initializeVar() {
            // initialization code goes here
        }
    }
    
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.