Statik ve statik olmayan bir başlatma kod bloğu arasındaki fark nedir


357

Sorum, statik anahtar kelimenin belirli bir kullanımı hakkında. staticHerhangi bir işleve ait olmayan bir sınıf içindeki kod bloğunu kapsamak için anahtar sözcük kullanmak mümkündür . Örneğin, aşağıdaki kod derlemeleri:

public class Test {
    private static final int a;    
    static {
        a = 5;
        doSomething(a);
    }
    private static int doSomething(int x) {
        return (x+5);
    }
}

staticAnahtar kelimeyi kaldırırsanız değişken aolduğu için şikayet eder final. Ancak hem anahtar kelimeleri hem de anahtar kelimeleri kaldırmak finalve staticderlemek mümkündür.

Benim için her iki şekilde de kafa karıştırıcı. Nasıl herhangi bir yönteme ait olmayan bir kod bölümü olması gerekir? Onu çağırmak nasıl mümkün olabilir? Genel olarak, bu kullanımın amacı nedir? Ya da daha iyisi, bununla ilgili belgeleri nereden bulabilirim?

Yanıtlar:


403

Statik değiştiricili kod bloğu bir sınıf başlatıcısı anlamına gelir ; statik değiştirici olmadan kod bloğu bir örnek başlatıcıdır.

Sınıf başlatıcılar, sınıf yüklendiğinde (aslında çözüldüğünde, ancak bu bir tekniktir) tanımlandıkları sırayla (yukarıdan aşağıya, basit değişken başlatıcılar gibi) yürütülür.

Örnek başlatıcıları, sınıf somutlaştırıldığında, yapıcı kodu yürütülmeden hemen önce, süper kurucunun çağrılmasından hemen sonra tanımlanan sırayla yürütülür.

Eğer kaldırırsanız staticgelen int a, bu bloğun başlatıcısı statik erişmek mümkün değildir bir örnek değişkeni haline gelir. Bu "statik olmayan değişken a statik bir bağlamdan başvurulamaz" hatası ile derlemek başarısız olur.

staticBaşlatıcı bloğundan da kaldırırsanız , o zaman bir örnek başlatıcı haline gelir ve böylece int ayapım aşamasında başlatılır.


Statik başlatıcı, yüklendikten ve bağlandıktan sonra sınıf başlatıldığında daha sonra çağrılır. Bu, bir sınıfın nesnesini başlatırken veya sınıftaki statik bir değişkene veya yönteme eriştiğinizde olur. Aslında statik bir başlatıcı ve bir yöntem ile bir sınıf public static void staticMethod(){}varsa, yürütmek TestStatic.class.getMethod("staticMethod");. Statik başlatıcı çağrılmaz. Daha fazla bilgi burada docs.oracle.com/javase/specs/jvms/se10/html/...
TOTO

@ Totò: Evet, sınıfın çözünürlüğünün gerektirdiği şey (en azından bunu bağlantı + init olarak "çözüm" olarak tanımlamak için kullandıkları zaman). Çözülmeden bir sınıf hakkındaki şeyleri keşfetmek için yansımayı kullanabileceğinize şaşırmadım .
Lawrence Dol

166

Uff! statik başlatıcı nedir?

Statik başlatıcı, static {}java sınıfı içindeki bir kod bloğudur ve yapıcı veya ana yöntem çağrılmadan önce yalnızca bir kez çalışır.

TAMAM! Bana daha fazlasını anlat...

  • static { ... }herhangi bir java sınıfının içindeki kod bloğudur . ve sınıf çağrıldığında sanal makine tarafından yürütülür.
  • returnDesteklenen hiçbir ifade yok .
  • Hiçbir bağımsız değişken desteklenmez.
  • Hayır thisveya superdestekleniyor.

Hmm nerede kullanabilirim?

Tamam hissediyorum her yerde kullanılabilir :) bu kadar basit. Ancak çoğu zaman veritabanı bağlantısı, API başlangıcı, Günlüğe kaydetme vb.

Sadece havlama! örnek nerede?

package com.example.learnjava;

import java.util.ArrayList;

public class Fruit {

    static {
        System.out.println("Inside Static Initializer.");

        // fruits array
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Pear");

        // print fruits
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        System.out.println("End Static Initializer.\n");
    }

    public static void main(String[] args) {
        System.out.println("Inside Main Method.");
    }
}

Çıktı???

İç Statik Başlatıcı.

elma

Portakal

Armut

Statik Başlatıcıyı Sonlandır.

İç Ana Yöntem.

Bu yardımcı olur umarım!


Teşekkürler Madan! Statik blok yerine kullanılabilir afterPropertiesSet()ait InitializingBean?
Alexander Suraphel

3
Evet yapabilirsin! Sınıf jvm tarafından yüklendiğinde statik başlatıcı çağrılır. Kodun yürütüldüğü ilk aşama budur. Bir kurucunuz da varsa, sıra şu olacaktır: statik başlatıcı, yapıcı, afterPropertiesSet
Martin Baumgartner

57

staticBlok "statik başlatıcı" dir.

Sınıf yüklendiğinde otomatik olarak çağrılır ve onu çağırmanın başka bir yolu yoktur (Yansıma yoluyla bile).

Şahsen sadece JNI kodu yazarken kullandım:

class JNIGlue {
    static {
        System.loadLibrary("foo");
    }
}

6
Hayır, onu çağırmanın açık bir yolu yok, sınıf başlatıcısı hiçbir zaman bir Methodörnek tarafından temsil edilmez, yalnızca Java sanal makinesi tarafından çağrılır.
Rafael Winterhalter

46

Bu doğrudan http://www.programcreek.com/2011/10/java-class-instance-initializers/ adresinden

1. Yürütme Emri

Aşağıdaki sınıfa bakın, hangisinin önce idam edildiğini biliyor musunuz?

public class Foo {

    //instance variable initializer
    String s = "abc";

    //constructor
    public Foo() {
        System.out.println("constructor called");
    }

    //static initializer
    static {
        System.out.println("static initializer called");
    }

    //instance initializer
    {
        System.out.println("instance initializer called");
    }

    public static void main(String[] args) {
        new Foo();
        new Foo();
    }
}

Çıktı:

statik başlatıcı denir

örnek başlatıcısı çağrıldı

denilen kurucu

örnek başlatıcısı çağrıldı

denilen kurucu

2. Java örneği başlatıcısı nasıl çalışır?

Yukarıdaki örnek başlatıcısı bir println ifadesi içeriyor. Nasıl çalıştığını anlamak için, bunu değişken atama ifadesi olarak ele alabiliriz, örn b = 0. Bu, anlaşılmasını daha açık hale getirebilir.

Onun yerine

int b = 0, yazabilirsin

int b;
b = 0;

Bu nedenle, örnek başlatıcıları ve örnek değişken başlatıcıları hemen hemen aynıdır.

3. Örnek başlatıcıları ne zaman yararlıdır?

Örnek başlatıcılarının kullanımı nadirdir, ancak yine de aşağıdaki durumlarda örnek değişken başlatıcılarına yararlı bir alternatif olabilir:

  1. Başlatıcı kodu istisnaları işlemelidir
  2. Bir örnek değişkeni başlatıcısı ile ifade edilemeyen hesaplamalar yapın.

Tabii ki, bu kod yapıcılara yazılabilir. Ancak bir sınıfın birden çok kurucusu varsa, kodu her kurucuda tekrarlamanız gerekir.

Bir örnek başlatıcısıyla, kodu bir kez yazabilirsiniz ve nesneyi oluşturmak için hangi kurucu kullanılırsa kullanılsın kod yürütülür. (Sanırım bu sadece bir kavram ve sık kullanılmıyor.)

Örnek başlatıcılarının yararlı olduğu başka bir durum, hiçbir kurucu bildiremeyen anonim iç sınıflardır. (Bu, bir kayıt işlevi yerleştirmek için iyi bir yer olacak mı?)

Derhein'a teşekkürler.

Ayrıca, arabirimleri uygulayan anonim sınıfların [1] yapıcıları olmadığını unutmayın. Bu nedenle, inşaat sırasında her türlü ifadeyi yürütmek için örnek başlatıcılara ihtiyaç vardır.


12

"final", bir değişkenin nesne başlatıcı kodunun sonundan önce başlatılması gerektiğini garanti eder. Benzer şekilde "statik son", bir değişkenin sınıf sonu başlatma kodu tarafından başlatılmasını garanti eder. Başlatma kodunuzdan "statik" değerini atlamak, onu nesne başlatma koduna dönüştürür; böylece değişkeniniz artık garantilerini karşılamıyor.


8

Programınızın herhangi bir yerinde çağrılması gereken statik bir bloğa kod yazmazsınız. Kodun amacı çağrılacaksa, bir yönteme yerleştirmeniz gerekir.

Sınıf yüklendiğinde statik değişkenleri başlatmak için statik başlatıcı blokları yazabilirsiniz, ancak bu kod daha karmaşık olabilir.

Statik bir başlatıcı bloğu, adı, argümanı ve dönüş türü olmayan bir yönteme benzer. Asla çağırmadığınız için bir isme ihtiyacı yoktur. Çağrıldığı tek zaman sanal makinenin sınıfı yüklediği zamandır.


6

bir geliştirici bir başlatıcı bloğu kullandığında, Java Derleyici başlatıcıyı geçerli sınıfın her yapıcısına kopyalar.

Misal:

aşağıdaki kod:

class MyClass {

    private int myField = 3;
    {
        myField = myField + 2;
        //myField is worth 5 for all instance
    }

    public MyClass() {
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

şuna eşittir:

class MyClass {

    private int myField = 3;

    public MyClass() {
        myField = myField + 2;
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        myField = myField + 2;
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

Umarım örneğim geliştiriciler tarafından anlaşılır.


4

Statik kod bloğu, sınıf değişkenlerini başlatmak veya başlatmak için kullanılabilir (nesne değişkenlerinin aksine). Dolayısıyla, "a" statikinin bildirilmesi, tüm Test nesneleri tarafından paylaşılan yalnızca bir anlamına gelir ve statik kod bloğu, Test sınıfı ilk kez yüklendiğinde, kaç Test nesnesi oluşturulmuş olursa olsun, yalnızca bir kez "a" değerini başlatır.


Takip olarak, nesnenin bir örneğini oluşturmazsam, bunun yerine genel bir statik işlev çağırırım. Bu bloğun, bu genel işlev çağrısından önce yürütüleceği garanti ediliyor mu? Teşekkürler.
Szere Dyeri

Sınıfın genel statik işlevini çağırırsanız, önce sınıfın yüklenmesi gerekir, bu nedenle evet, önce statik başlatıcı çalıştırılır.
Paul Tomblin

Sınıf başlangıcı olmadığı sürece (dolaylı olarak) onu kullanmaya çalışan kodu çağırdı. IFYSWIM. Dairesel bağımlılıklar ve hepsi.
Tom Hawtin - tackline

1
@Tom haklı - başka bir statik başlatıcı çağrılmadan önce bir statik başlatıcısının statik bir yöntem çağırdığı bir şey yazmak mümkündür, ancak zihnim düşüncede geri teper, bu yüzden hiç düşünmedim.
Paul Tomblin
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.