الكلمة المفتاحية static في الجافا

ينقسم استخدام الكلمة المفتاحية static في الجافا إلى عدة حالات بالشكل التالي:

الحقل أو العضو البياني ستاتيكي static data member

تستخدم الكلمة static في الجافا قبل عضو بياني معين لجعل هذا العضو مشتركاً بين جميع أغراض الصف، ففي لغة الجافا عند إنشاء كائنات من صف معين يملك كل كائن نسخته الخاصة من الأعضاء البيانية وأي تغيير في عضو بياني ضمن كائن معين لا يؤثر أبداً على بقية الكائنات.

للتوضيح لنفرض ان لدينا صف A يملك حقلاً (عضواً بيانياً) count من نمط int بالشكل التالي:

/**
 *
 * @author Mutasem
 */
public class A {
   private int count = 0;
    public A() {
        count++;
        System.out.println("count: " + count);
    }
}

لنقم بإنشاء ثلاثة كائنات من هذا الصف

public static void main(String[] args) {      
   A a = new A();  
   A a1 = new A();        
   A a2 = new A();     
}

عند التنفيذ سنلاحظ الناتج التالي:

count: 1 count: 1 count: 1

السبب هو أن كل كائن من الكائنات الثلاثة يملك نسخة مختلفة من الحقل count بالتالي زيادة هذا العداد في كائن ما لاتؤثر على بقية الكائنات.

في بعض الحالات يتطلب الأمر وجود حقل مشترك بين جميع الكائنات، مثلاً لعمل عداد للكائنات سنستخدم نفس المثال السابق مع تعديل بسيط بالشكل التالي:

public class A {
    private int count = 0;
    private static int count = 0;

    public A() { 
    count++; 
    System.out.println(“count: ” + count);    
  }
}

هذه المرة سيكون خرج البرنامج بالشكل التالي:

count: 1 count: 2 count: 3

بعد وضع الكلمة المفتاحية قبل تعريف الحقل count أصبح هذا الحقل مشتركاً بين جميع الكائنات وبالتالي أي تعديل على هذا الحقل ضمن كائن معين يؤثر على جميع الكائنات.

الدالة ستاتيكية static method

لاستدعاء دالة معينة موجودة في صف علينا إنشاء كائن من هذا الصف ومن ثم استدعاء الدالة عن طريق الكائن مثال

public class A {
    private int count = 0;
    private static int count = 0;

    public A() {
        count++;
        System.out.println("count: " + count);
    }

    public void m() {
        count++;
        System.out.println("count: " + count);
    }
}

/*******************************/
public static void main(String[] args) {
    A a = new A();
    A a1 = new A();
    A a2 = new A();
    a.m();
    a.m();
    a1.m();
}

ويكون خرج البرنامج

count: 1 count: 1 count: 1 count: 2 count: 3 count: 2

ولا يمكن لنا أن نقوم باستدعاء الدالة m دون إنشاء كائن، كأن نقوم مثلاً بالاستدعاء التالي:

A.m();//error

لكن هذا الاستدعاء يصبح صحيحاً إذا قمنا بتعديل الدالة m لتصبح دالة ستاتيكية كما يلي:

public class A {
    private int count = 0;
    private static int count = 0;

    public A() {
        count++;
        System.out.println("count: " + count);
    }

    public static void m() {
        count++;
        System.out.println("count: " + count);
    }
}

/***************/
public static void main(String[] args) {
    A a = new A();
    A a1 = new A();
    A a2 = new A();
    a.m();
    a.m();
    a1.m();
    A.m();
    A.m();
    A.m();
}

ويكون الخرج

count: 1 count: 2 count: 3

ملاحظة

 لاستخدام الحقل count مع الدالة m اضطررنا لجعل الحقل ستاتيكي وذلك لأنه لايمكن لدالة ستاتيكية التعامل مع حقل غير ستاتيكي.

الصف ستاتيكي static class

هو صف داخلي يمكن إنشاء كائن منه دون الحاجة لإنشاء كائن من الصف الحاوي.

بفرض لدينا الصف A يحوي بداخله الصف B، إذا لم يكن B صف ستاتيكي فإنه من غير الممكن إنشاء كائن من B دون إنشاء كائن من A، أما حين يكون B ستاتيكي يمكننا إنشاء كائن من B دون الحاجة لإنشاء كائن من A.

مثال

public class A {
    public class B {
        public B() {
            System.out.println("I am B Who R U?");
        }
    }

    private int count = 0;
    private static int count = 0;

    public A() {
        count++;
        System.out.println("count: " + count);
    }

public static void m() {  count++;  System.out.println("count:
" + count);  }

    public

            void m() {
        count++;

        System.out.println("count: " + count);
    }

    }

    /**********************/

public static void main(String[] args) {
     A a = new A(); 
     A
a1 = new A(); 
 A a2 = new A(); 
 a.m(); 
 a.m();
// a1.m(); 
 A.m();
 A.m(); 
 A.m(); 
A a = new A();  A.B b = a.new B(); 
A.B b=new B(); 
  }

لاحظ لإنشاء كائن من B اضطررنا لإنشاء كائن من A أولاً ثم عن طريق هذا الكائن قمنا بإنشاء كائن من B ويكون الخرج كما يلي:

count: 1 I am B Who R U ?

سنقوم بتعديل الصف B ليصبح ستاتيكي بالشكل التالي

public static class B {
    public B() {
        System.out.println("I am B Who R U?");
    }
}

ويصبح إنشاء الكائن بالشكل التالي:

package example.mutasem4it.statictest;

import example.mutasem4it.statictest.A.B;

/**
 *
 * @author Mutasem
 */
public class MainClass {

    public static void main(String[] args) {
        // A a = new A();
        // A a1 = new A();
        // A a2 = new A();
        // a.m();
        // a.m();
        // a1.m();
        // A.m();
        // A.m();
        // A.m();
        // A a=new A();
        // A.B b=a.new B();
        A.B b = new B();
    }

}

وبتنفيذ البرنامج نحصل على الخرج التالي

I am B Who R U ?

لاحظ لم يتم استدعاء الباني الخاص ب A أبداً.

البلوك ستاتيكي static block

هو قطعة من الكود البرمجي يتم تنفيذها لمرة واحدة فقط عند إنشاء أول كائن من الصف ويستخدم غالباً لتهيئة الأعضاء البيانية ستاتيكية كما في المثال التالي:

private static ArrayList<String> words;
    static {
    words=new  ArrayList<>();
    words.add("Hi");
    words.add("I am");
    words.add("Mutasem");
    
    }

مع نهاية هذه الفقرة أكون قد أنهيت مقالتي ولفهم أكثر اقترح عليك تجربة الأمثلة بنفسك والوقوف على كل حالة.

رابط المشروع على GitHub

https://github.com/mutasemhajhasan/Java-Static-Keyword