Java'da statik blok yürütülmedi


87
class Test {
    public static void main(String arg[]) {    
        System.out.println("**MAIN METHOD");
        System.out.println(Mno.VAL); // SOP(9090);
        System.out.println(Mno.VAL + 100); // SOP(9190);
    }

}

class Mno {
    final static int VAL = 9090;
    static {
        System.out.println("**STATIC BLOCK OF Mno\t: " + VAL);
    }
}

staticSınıf yüklendiğinde bir bloğun çalıştırıldığını biliyorum . Ancak bu durumda örnek değişkeni içinde sınıf Mnoolduğunu finalbundan dolayı, staticblok yürütülmüyor.

Neden böyle? Ve eğer çıkarırsam final, iyi çalışır mı?

İlk olarak hangi bellek tahsis edilecek, static finaldeğişken staticmi yoksa blok mu?

Nedeniyle Eğer finalerişim değiştirici sınıf girmiyordu, o zaman nasıl değişken olsun hafıza can?


1
Aldığınız tam hata ve mesaj nedir?
Patashu

@Patashu, hata yok, şüphe yok
Sthita

Yanıtlar:


135
  1. Bir static final intalan, bir derleme zamanı sabiti ve değeri kökeni için bir referans olmadan hedef sınıfına kodlanmış;
  2. bu nedenle, ana sınıfınız alanı içeren sınıfın yüklenmesini tetiklemez;
  3. bu nedenle bu sınıftaki statik başlatıcı çalıştırılmaz.

Ayrıntılı olarak, derlenen bayt kodu şuna karşılık gelir:

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(9090)
    System.out.println(9190)
}

Kaldırdığınız anda final, bu artık bir derleme zamanı sabiti değildir ve yukarıda açıklanan özel davranış geçerli değildir. MnoSınıf beklediğiniz gibi yüklenir ve yürütür başlatıcısı olan statik edilir.


1
Peki sınıftaki son değişkenin değeri, sınıf yüklenmeden nasıl değerlendirilir?
Sumit Desai

18
Tüm değerlendirme derleme zamanında gerçekleşir ve sonuç, değişkene referans veren tüm yerlere kodlanır.
Marko Topolnik

1
Öyleyse, ilkel bir değişken yerine, bir Nesne ise, o zaman böyle kodlama mümkün olmayacaktır. Değil mi? Peki, bu durumda, bu sınıf yüklenecek ve statik blok çalıştırılacak mı?
Sumit Desai

2
Marko, Sumit'in şüphesi de haklı, eğer ilkel yerine, bir Nesne ise, o zaman böyle kodlama mümkün olmayacak. Değil mi? Peki, bu durumda, bu sınıf yüklenecek ve statik blok çalıştırılacak mı?
Sthita

8
@SumitDesai Kesinlikle, bu yalnızca ilkel değerler ve dize değişmezleri için çalışır. Tüm ayrıntılar için Java Dil Spesifikasyonundaki ilgili bölümü
Marko Topolnik

8

Sınıf yüklenmez nedeni olmasıdır VALolup final VE bunun başlangıç durumuna geri döner sabit ifadesi (9090). Yalnızca ve ancak bu iki koşul karşılanırsa, sabit derleme zamanında değerlendirilir ve gerektiğinde "kodlanır".

İfadenin derleme zamanında değerlendirilmesini önlemek (ve JVM'nin sınıfınızı yüklemesini sağlamak için) aşağıdakilerden birini yapabilirsiniz:

  • son anahtar kelimeyi kaldırın:

    static int VAL = 9090; //not a constant variable any more
    
  • veya sağ taraftaki ifadeyi sabit olmayan bir şeye değiştirin (değişken hala son olsa bile):

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    

5

Kullanılarak oluşturulan bayt kodunu görürseniz javap -v Test.class, main () şu şekilde çıkar:

public static void main(java.lang.String[]) throws java.lang.Exception;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String **MAIN METHOD
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: sipush        9090
        14: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        17: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        20: sipush        9190
        23: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        26: return        

11: sipush 9090Mno.VAL bir derleme zamanı sabiti olduğundan statik son değerin doğrudan kullanıldığını " " içinde açıkça görebilirsiniz . Bu nedenle Mno sınıfının yüklenmesine gerek yoktur. Bu nedenle, Mno'nun statik bloğu yürütülmez.

Mno'yu aşağıdaki gibi manuel olarak yükleyerek statik bloğu çalıştırabilirsiniz:

class Test{
    public static void main(String arg[]) throws Exception {
        System.out.println("**MAIN METHOD");
        Class.forName("Mno");                 // Load Mno
        System.out.println(Mno.VAL);
        System.out.println(Mno.VAL+100);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}

1
  1. Aslında bu Mno sınıfını genişletmediniz, bu yüzden derleme başladığında VAL değişkeninin sabitini üretecek ve yürütme, bu değişkene ihtiyaç duyulduğunda bellekten gelen yükü gerektiğinde başlayacaktır. Dolayısıyla, statik bock'un çalıştırılmaması için sınıf referansınızın olması gerekmez.

  2. sınıf sınıfı Agenişletirse Mno, statik blok sınıfa dahil edilir, Abunu yaparsanız o statik blok çalıştırılır. Örneğin..

    public class A extends Mno {
    
        public static void main(String arg[]){    
            System.out.println("**MAIN METHOD");
            System.out.println(Mno.VAL);//SOP(9090);
            System.out.println(Mno.VAL+100);//SOP(9190);
        }
    
    }
    
    class Mno {
        final static int VAL=9090;
        static {
            System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
        }
    }
    

0

Bildiğim kadarıyla, ortaya çıkma sırasına göre yürütülecek. Örneğin :

 public class Statique {
     public static final String value1 = init1();

     static {
         System.out.println("trace middle");
     }
     public static final String value2 = init2();


     public static String init1() {
         System.out.println("trace init1");
         return "1";
     }
     public static String init2() {
         System.out.println("trace init2");
         return "2";
     }
 }

yazdıracak

  trace init1
  trace middle
  trace init2

Sadece test ettim ve "Statique" sınıfı gerçekten kullanıldığında ve başka bir kod parçasında "yürütüldüğünde" (benim durumumda "new Statique ()" yaptım.


2
Bu çıktıyı Statique, yaparak sınıfı yüklediğiniz için alıyorsunuz new Statique(). Sorulan soruda Mnosınıf hiç yüklenmedi.
RAS

@Fabyen, şu şekilde test sınıfında Mno nesnesini oluşturuyorsam: Mno anc = New Mno (); o zaman iyi, ama mevcut senaryo bunu yapmıyorum, şüphem eğer finali kaldırıyorsam statik blok iyi çalışır, aksi takdirde çalışmaz, neden öyleyse ??
Sthita

1
Evet, aşağıdaki cevap mükemmel. Main.class bayt kodunda (Mno.VAL kullanılarak), 9090 sabit kodlanmış olarak bulunur. Sonu kaldırın, derleyin, ardından javap Main'i kullanın, getstatic # 16 göreceksiniz ; // Alan Statique.VAL: Ben . Finali geri koyun, derleyin, ardından javap Main'i kullanın, sipush 9090'ı göreceksiniz .
Fabyen

1
Main.class içinde kodlandığı için, MNO sınıfını yüklemenin bir nedeni yoktur, dolayısıyla statik başlatma yoktur.
Fabyen

Bu, ikinci soruyu yanıtlar: "İlk olarak hangi bellek tahsis edilecek, statik son değişken mi yoksa statik blok mu?" (sözcük sıralaması)
Hauke ​​Ingmar Schmidt
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.