الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

الـ Binary Serialization في الجافا

بدأه Snack3r في 26 نوفمبر 2013 · 4 رد · 843 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم و رحمة الله و بركاته

 

 

الفهرس :

  1. ما هي عملية الـ Serialization ؟
  2. كيف نقوم بها ؟
  3. مثال تطبيقي
  4. متى نستخدم transient ؟
  5. الواجهة البديلة Externalizable
  6. اختبر قدراتك في الـ Serialization

 

1. ما هي عملية الـ Serialization ؟

الـ Serialization عبارة عن آلية تسمح بحفظ الكائنات في storage medium أي وسيلة تخزين مثل الملفات أو ذاكرات التخزين المؤقت (memory buffer) كما تُمكن أيضا من نقل الكائنات عبر شبكات الاتصال, تم دعمها في الجافا ابتداء من النسخة 1.1 من الـ JDK, تسمح هذه الآلية بالحفاظ على الـ Object Persistence حيث تُنقل الكائنات عبر binary support على شكل مجموعة من الـ bytes أو على شكل قابل للقراءة مثل ملفات XML. الـ format المستخدم لحفظ الكائنات لا علاقة له بنظام التشغيل حيث يُمكن إعادة بناء الكائن (تُسمى هذه العملية بـ deserialization) في نظام تشغيل مختلف عن الذي تمت فيه عملية الـ serialization.

أثناء هذه العملية, يُمكن تخزين الكائنات على القرص الصلب أو في قاعدة بيانات كما يُمكن أيضاً إعادة بنائها في جهاز آخر في الشبكة حيث تتم إعادة إنشائها باستخدام الـ JVM الموجودة في الجهاز المستقبِل. (كما تفعل RMI مثلا)

في هذه المقالة, سنشرح كيفية عمل الـ binary serialization مع العلم أنه يُمكن عمل الـ XML serialization في الجافا باستخدام الفئتين XMLEncoder و XMLDecoder حيث يتم تخزين البيانات بصيغة XML.

 

 

2. كيف نقوم بالـ Serialization

تعتمد الـ serialization على الـ streams لذا يجب أن تكون لديك معرفة مُسبقة بمعظم الفئات الموجودة في الحزمة java.io و كيفية التعامل معها. تُوفر الـ Java API الأدوات اللازمة لعمل الـ serialization و هي :

  • الواجهة Serializable
  • الفئتين ObjectOutputStream و ObjectInputStream

الواجهة Serializable تسمح بتحديد الفئة التي نُريد عمل serialization لها, الفئتين ObjectOutputStream و ObjectInputStream يُمكّنان (على التوالي) من تحديد كيف ستتم عملية الــ serialization و الـ  deserialization.

 

2.1 - الواجهة Serializable

لعمل serialization لكائن من فئة معينة, يجب على هذه الفئة أن تقوم بعمل implements للواجهة Serializable أو ترث فئة قامت مُسبقاً بعمل implements للواجهة Serializable.

لا تحتوي الواجهة Serializable على أي دالة حيث يقتصر دورها على تحديد فئة معينة كــ serializable.

يتم عمل الـ serialization لكافة حقول الكائن باستثناء تلك الغير serializable أو تلك التي تم الإعلان عنها باستخدام الكلمة static أو transient.

 

ملاحظات :

  • جميع الأنواع الأساسية (مثل int, long, float, ...) يُمكن عمل serialization لها.
  • ليست كل الكائنات serializable فقد تكون مرتبطة بنظام التشغيل أو مرتبطة بسياق التنفيذ في الذاكرة مثل الـ Threads.
  • أصبحت File فئة serializable في النسخ الحديثة من جافا.
  • إذا حاولت عمل serialization لكائن من فئة لم تقم بعمل implements للواجهة Serializable, سيتم إصدار استثناء من نوع NotSerializableException.
  • استخدم الأداة Serialver من سطر الأوامر لتحديد هل الفئة تدعم الـ serialization أم لا, أمثلة :
    serialver java.awt.Graphics
    
    Class java.awt.Graphics is not Serializable.
    
    ----
    
    serialver java.io.File
    
    java.io.File: static final long serialVersionUID = 301077366599181567L;
  • الـ serialVersionUID عبارة عن رقم النسخة حيث يوجد في كل فئة قامت بعمل implements للواجهة Serializable, الهدف منه هو ضمان تطابق الفئة عند عمل الـ deserialization, وإذا تغيرت الفئة بين عمليتي الـ serialization و deserialization, يتم إصدار استثناء من نوع InvalidClassException.
  • كل فئة serializable يجب أن تُعلن بشكل صريح عن المتغير serialVersionUID حيث يجب أن يكون final, static و من نوع long أيضاً, مثال :
    private static final long serialVersionUID = 42L;
  • إذا لم تقم الفئة بالإعلان عن الحقل serialVersionUID, تتولى آلية الـ serialization توليد رقم تسلسلي للفئة بشكل تلقائي.

 

2.2 - الفئتان ObjectOutputStream و ObjectInputStream

ورثت الواجهتان ObjectOutput و ObjectInput خصائص الواجهتين DataOutput و  DataInput و أضافتا إمكانية كتابة/قراءة الكائنات, تحتوي كل من DataOutput و  DataInput على دوال تُمكن من كتابة/قراءة الأنواع الأولية (مثل char, long, double, ..) حيث أضافت ObjectOutput و ObjectInput إمكانية كتابة/قراءة المصفوفات و الكائنات.

قامت كل من ObjectOutputStream و ObjectInputStream على التوالي بعمل implements لـ ObjectOutput|ObjectInput.

كلا الفئتين ObjectOutputStream و ObjectInputStream عبارة عن stream object, حيث يسمحان بعمل serialization/deserialization لكائن معين, على التوالي باستخدام إحدى الدالتين writeObject/readObject.

 

3. مثال تطبيقي

نبدأ مع الفئة التي سيتم عمل serialization لها :

public class User implements java.io.Serializable {

    private String login;
    private String password;

    public User() {
        this("anonymous", "");
    }

    public User(String login, String password) {
        this.login = login;
        this.password = password;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User -> Login : " + this.getLogin() + "\t Password : "
                + (password.equals("") ? "(nothing)" : this.getPassword());
    }

    public static void main(String[] args) {
        User user = new User("Snack3r", "#_#Sn@CkeRC00L");
        System.out.println(user.toString());
        User anonym = new User();
        System.out.println(anonym.toString());
    }
}

و هذه الفئة المسئولة عن الـ Serialization :

import java.io.*;

public class Serialization {

    public File serializeUser(User u) {
        try {
            System.out.println("Création de : " + u.toString());
            File fichier = new File("C:\\Users\\Snacker\\Desktop\\user.ser");
            FileOutputStream fos = new FileOutputStream(fichier);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            try {
                oos.writeObject(u);
                oos.flush();
                System.out.println(u + " a été sérialisé");
                return fichier;
            } finally {
                try {
                    oos.close();
                } finally {
                    fos.close();
                }
            }
        } catch (IOException ioe) {
            System.err.println("Une exception de type Input/Output est declanchée");
            return null;
        }
    }

    public static void main(String... args) {
        User utilisateur = new User("Mohamed AHMED", "123456");
        new Serialization().serializeUser(utilisateur);
    }
}

تستقبل الدالة serializeUser كائناً من نوع User و تُعيد كائناً من نوع File, يُمثل الملف الذي تمت فيه عملية الـ serialization.

في البداية, قمنا بإنشاء الملف الذي سيحوي الـ serialized object (في الحقيقة, الملف سيُخزن فقط حقول الكائن) و باستخدام الفئة FileOutputStream, قمنا بإرفاق stream writing للكائن fichier, ثم قمنا بكتابة بيانات المستخدم u داخل كائن الـ output stream باستخدام الدالة writeObject لنقوم بعد ذلك بإفراغ محتوى الـ oos باستخدام الدالة flush.

مُخرجات الكود :

Création de : User -> Login : Mohamed AHMED    Password : 123456
User -> Login : Mohamed AHMED Password : 123456 a été sérialisé

نأتي الآن إلى الفئة المسئولة عن الـ Deserialization :

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Deserialization {

    public void deserializeUser(String chemin) {
        User u = null;
        try {
            FileInputStream fis = new FileInputStream(chemin);
            ObjectInputStream ois = new ObjectInputStream(fis);
            u = (User) ois.readObject();
            System.out.println("~OoO~ -------------------------------------- ~OoO~");
            System.out.println("Les données de l'objet qui était sérialisé sont :");
            System.out.println(u.toString());
            System.out.println("~OoO~ -------------------------------------- ~OoO~\n");
        } catch (IOException ioe) {
            System.err.println("Une exception de type Input/Output est déclanchée");
        } catch (ClassNotFoundException cnfe) {
            System.err.println("Une exception de type ClassNotFoundException est déclanchée");
        }
        if (u != null) {
            System.out.println("[ " + u + " ] a été dé-sérialisé");
        }
    }

    public static void main(String... args) {
        new Deserialization().deserializeUser("C:\\Users\\Snacker\\Desktop\\user.ser");
    }
}

في البداية, قمنا بإنشاء كائن من FileInputStream يُمثل stream reading للملف الموجود في المسار chemin ثم قمنا بالإعلان عن كائن من ObjectInputStream من أجل إعادة بناء الكائن u باستخدام الدالة readObject.

لاحظ أننا قمنا بعمل casting للحصول على النوع الحقيقي للـ serialized object.

بطبيعة الحال, يجب أن تتم الـ deserialization بنفس الفئة التي تمت بها عملية الـ serialization. (بغض النظر عن المفاهيم البرمجية, يُمكننا استنتاج هذه الملاحظة اعتماداً على المنطق السليم).

يتم إصدار استثناء من نوع StreamCorruptedException إذا تم تغيير محتوى الملف من خلال editor مثلا. يُمكن أيضاً إصدار استثناء من نوع ClassNotFoundException إذا تم تحويل الكائن إلى فئة لم يتم العثور عليها أثناء التنفيذ.

 

 

مُخرجات الكود :

~OoO~ -------------------------------------- ~OoO~
Les données de l'objet qui était sérialisé sont :
User -> Login : Mohamed AHMED Password : 123456
~OoO~ -------------------------------------- ~OoO~

[ User -> Login : Mohamed AHMED    Password : 123456 ] a été dé-sérialisé

4. متى نستخدم transient ؟

يُمكن رؤية محتوى المتغيرات من خلال الـ stream الذي تمت عملية الـ serialization بداخله و بالتالي يُمكن لأي شخص يستطيع الوصول إلى الـ stream, رؤية محتوى مختلف المتغيرات حتى لو كانت private و هذا يُمكن أن يُؤدي إلى وجود العديد من المشاكل التي تُهدد حماية البيانات, خصوصاً عند نقل معلومات حساسة عن طريق الشبكة. لهذا السبب قامت Java بتوفير الكلمة المحجوز transient التي تعني أن المتغير المرافق لها ينبغي عدم إدراجه في عملية الـ serialization و بالتالي الـ deserialization.

للتأكد, يُمكنك تجربة transient مع  المتغير الخاص بكلمة المرور في الفئة User.

أثناء عملية الـ deserialization يتم إسناد القيمة null للمتغيرات التي تم الإعلان عنها باستخدام transient و هذا جيد من ناحية لكن في نفس الوقت قد يؤثر على عمل الدوال التي تستخدم تلك المتغيرات حيث سيتم إصدار استثناء من نوع NullPointerException.

 

 

5. الواجهة البديلة Externalizable

رأينا سابقاً كيفية عمل serialization من خلال كتابة كائن بمجمله في stream و إعادة بنائه من جديد. قد نحتاج في بعض الأحيان إلى عمل الـ serialization لمتغيرات معدودة لكائن معين لذا توفر جافا الواجهة البديلة Externalizable التي تُمكن من السيطرة الكاملة على عملية الـ serialization. (مع العلم أن الواجهة Externalizable قامت بعمل implements للواجهة Serializable)

تحتوي الواجهة البديلة على دالتين هما writeExternal و readExternal, من خلال إعادة تعريفهما سنحدد المتغيرات التي ستدخل في عملية الـ serialization.

وفقاً للحالة الافتراضية للواجهة Externalizable, لا تأخذ عملية الـ serialization في الاعتبار أي من متغيرات الكائن لذا لا فائدة من استخدام transient في هذه الحالة.

عند إعادة تعريف الدالة readExternal ستحتاج إلى استخدام دوال DataInput للأنواع الأولية (مثل char, long, double, ..) و readObject للكائنات (مثل String, Object, Arrays ..). نفس الشيء بالنسبة للدالة writeObject و الواجهة DataOutput مع writeExternal.

 

لنأخذ الفئة User كمثال :

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class User implements Externalizable {

    private int id;
    private String login;
    private String password;

    public User() {
        this(-1, "anonymous", "");
    }

    public User(int id, String login, String password) {
        this.id = id;
        this.login = login;
        this.password = password;
    }

    public int getID() {
        return id;
    }

    public void setID(int id) {
        this.id = id;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User -> Login : " + this.getLogin() + "\t Password : "
                + (password.equals("") ? "(nothing)" : this.getPassword());
    }

    @Override
    public void writeExternal(ObjectOutput e) {
        try {
            System.out.println("-> starting writing...");
            e.writeInt(this.getID());
            e.writeObject(this.getLogin());
            e.writeObject(this.getPassword());
            e.flush();
            e.close();
            System.out.println("-> finishing writing !\n");
        } catch (IOException ioe) {
            System.out.println("Erreur reading...");
        }
    }

    @Override
    public void readExternal(ObjectInput e) {
        try {
            System.out.println("-> starting reading...");
            System.out.println("ID : " + e.readInt());
            System.out.println("Login : " + e.readObject());
            System.out.println("Password : " + e.readObject());
            System.out.println("-> finishing reading !\n");
        } catch (IOException | ClassNotFoundException ex) {
            System.out.println("Erreur reading...");
        }
    }
}

و هذه الفئة المسئولة عن الـ serialization/deserialization :
 

import java.io.*;
public class Test {

    public static void main(String args[]) {
        User u = new User(4507, "Snack3r", "#_#Sn@CkeRC00L");
        try {
            File fichier = new File("C:\\Users\\Snacker\\Desktop\\user.ser");
            FileOutputStream fos = new FileOutputStream(fichier);
            ObjectOutput oos = new ObjectOutputStream(fos);
            u.writeExternal(oos);
            FileInputStream fis = new FileInputStream(fichier);
            ObjectInputStream ois = new ObjectInputStream(fis);
            u.readExternal(ois);
        } catch (IOException ioe) {
            System.out.println("Erreur main");
        }
    }
}

مُخرجات الكود :

-> starting writing...
-> finishing writing !

-> starting reading...
ID : 4507
Login : Snack3r
Password : #_#Sn@CkeRC00L
-> finishing reading !

6. اختبر قدراتك في الـ Serialization

قم بإنشاء فئة باسم CompteBank تُمكن من التعامل مع حسابات بنكية مع الأخذ بعين الاعتبار حساسية المبالغ المالية للزبناء. يتم تعريف كل حساب بالرقم التسلسلي, الاسم الكامل لصاحب الحساب, رصيد الحساب, بالإضافة إلى الضمان المالي.

تتم عملية الـ serialization في ملف بامتداد ser يُخزن على سطح المكتب. قم بعمل الـ deserialization و أظهر أسماء أصحاب الحسابات.

قم بإنشاء فئة أخرى باسم Client, يتم تعريف كل زبون برقم بطاقة الهوية (IC) بالإضافة إلى الاسم الكامل.

قم بعمل الـ serialization في نفس الملف السابق الذي تم تخزينه على سطح المكتب ثم قم بعمل deserialization لجميع الكائنات الموجودة في الملف و أظهر أسماء الزبناء بجانب الضمان المالي لكل حساب.

 

 

 

 

تحياتي.

 

 

post-219439-019877100%201344289598.gif

تم تعديل هذه المشاركة بواسطة Snack3r في 27 نوفمبر 2013 في 03:26 — السبب: تنسيق الموضوع.

3
#2

جزاك الله خيراً :)

درس رائع ومفيد جداَ .. ولكن يبدو أن عندي بعض المشاكل في التعامل مع الملفات .. ثم كيف سنعرف عدد الكائنات وما هو نوعها المجودة في الملف ,,

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

الفئة CompteBank .. وفيها الدالة main أيضاً ..

package SerializetionTutorial.MyTest;

import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;

public class CompteBank implements Serializable{
    private static final long serialVersionUID = 1L;
    private String id;
    private String name;
    private transient long balance;
    private long warranty;
    
    public CompteBank(){
        
    }
    public CompteBank(String id, String name, long balance, long warranty) {
        this.id = id;
        this.name = name;
        this.balance = balance;
        this.warranty = warranty;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public long getBalance() {
        return balance;
    }
    public void setBalance(long balance) {
        this.balance = balance;
    }
    public long getWarranty() {
        return warranty;
    }
    public void setWarranty(long warranty) {
        this.warranty = warranty;
    }
    public static long getSerialversionuid() {
        return serialVersionUID;
    }
    @Override
    public String toString() {
        return "[id = "+id+",name="+name+",balance="+balance+",warranty="+warranty+"]";
    }
    static public File serialize(CompteBank[] users) {
        try {
            File fichier = new File("C:\\Users\\Mostafa36a2\\Desktop\\bank.ser");
            FileOutputStream fos = new FileOutputStream(fichier);
            ObjectOutputStream oos= new ObjectOutputStream(fos);
            for(CompteBank y:users)
                oos.writeObject(y);
            oos.flush();
            oos.close();
            fos.close();
            return fichier;
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return null;
    }
    static public ArrayList<CompteBank> deserialize(File fi,boolean withPrint){
        try {
            FileInputStream fis=new FileInputStream(fi);
            ObjectInputStream ois=new ObjectInputStream(fis);
            
            ArrayList<CompteBank>readed=new ArrayList<CompteBank>();
            try{
            while(true)
                {
                    readed.add((CompteBank)ois.readObject());
                    if(withPrint)
                        System.out.println("Name : "+readed.get(readed.size()-1).getName());
                }
            }catch(EOFException eof){
            ois.close();
            fis.close();
            return readed;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[]args){
        CompteBank users []=new CompteBank[]{
        new CompteBank("00985476321", "Hello World!", 100 , 100),
        new CompteBank("00985469854", "Snack3er", 10000 , 65100),
        new CompteBank("00980101004", "Abd Allatif", 14700 , 18900),
        new CompteBank("00980101004", "أحمد أبو عبد البر", 14700 , 18900),
        new CompteBank("00948940978", "Mostafa 36a2", 0x36a2 , 23)    
    };
        File y = CompteBank.serialize(users);
        ArrayList <CompteBank>cbs=
                CompteBank.deserialize(y,true);
        System.out.println("-------------------------------");
        Client clients []=new Client []{
                new Client("8900985476321", "Hello World!"),
                new Client("4500985469854", "Snack3er"),
                new Client("2000980101004", "Abd Allatif"),
                new Client("0700980101004", "أحمد أبو عبد البر"),
                new Client("5400948940978", "Mostafa 36a2")    
            };
        Client.serialize(clients);
        
        Client.deserialize(y,true);
        System.out.println("---------------------");
        for(CompteBank x:cbs)
            System.out.println("Client "+x.getName()+" has "+x.getWarranty());
    }
}

الفئة  Client

package SerializetionTutorial.MyTest;

import java.io.*;
import java.util.ArrayList;

public class Client implements Serializable{
    private static final long serialVersionUID = 2L;
    private String IC;
    private String name;
    public Client(String iC, String name) {
        IC = iC;
        this.name = name;
    }
    
    public String getIC() {
        return IC;
    }
    public void setIC(String iC) {
        IC = iC;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    static public File serialize(Object[] users) {
        try {
            File fichier = new File("C:\\Users\\Mostafa36a2\\Desktop\\bank.ser");
            FileOutputStream fos = new FileOutputStream(fichier);
            ObjectOutputStream oos= new ObjectOutputStream(fos);
            for(Object y:users)
                oos.writeObject(y);
            oos.flush();
            oos.close();
            fos.close();
            return fichier;
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return null;
    }
    static public ArrayList<Client> deserialize(File fi,boolean withPrint){
        try {
            FileInputStream fis=new FileInputStream(fi);
            ObjectInputStream ois=new ObjectInputStream(fis);
            
            ArrayList<Client>readed=new ArrayList<Client>();
            try{
            while(true)
                {
                    readed.add((Client)ois.readObject());
                    if(withPrint)
                        System.out.println("Client Name : "+readed.get(readed.size()-1).getName());
                }
            }catch(EOFException eof){
            ois.close();
            fis.close();
            return readed;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

الكود بحاجة إلى تحسينات كثيرة ولكن أظن ان هناك أخطاء جوهرية أنتظر تنبيهي إليها :)

بالتوفيق

تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 27 نوفمبر 2013 في 14:51

1
#3
اقتباس

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

 

 

يا رااجل .. ليش ما بتراسلني ع الخاص .. ممكن يكون في أعضاء آخرين يريدون المشاركة :D

 

اقتباس
كيف سنعرف عدد الكائنات وما هو نوعها المجودة في الملف

 

 

استخدم HashMap و قم بتخزين كائنات CompteBank بمفاتيح زوجية وClient بمفاتيح فردية مثلا. (في هذه الحالة, قم بعمل الـ serialization لكائن الـ HashMap داخل الملف bank.ser)

 

ملاحظاتي على محاولتك :

  • إذا اعتبرت أن محتوى المتغير balance غير serializable فمن الخطأ إعادة قيمته في الدالة toString.
  • أين الدوال التي تُمكن من شحن الحساب و سحب مبلغ في الفئة CompteBank ؟
  • كل مستخدم يجب أن يكون بإمكانه إجراء عمليات على حسابه.
#4
اقتباس

 

استخدم HashMap و قم بتخزين كائنات CompteBank بمفاتيح زوجية وClient بمفاتيح فردية مثلا. (في هذه الحالة, قم بعمل الـ serialization لكائن الـ HashMap داخل الملف bank.ser)

 

 

فكرة رائعة :) ولكن قصدت من سؤالي : هل يوجد طريقة لمعرفة نوع الكائن بمجرد سحبه من الملف ؟ أظن أنه بالإمكان اعتباره Object ثم اختبار instance ما رأيك ؟ (قمت بتجربتها ونجحت بشكل رائع ;) )

أيضاً ..

 

اقتباس

 

أين الدوال التي تُمكن من شحن الحساب و سحب مبلغ في الفئة CompteBank ؟

كل مستخدم يجب أن يكون بإمكانه إجراء عمليات على حسابه.

 

 

لما يكون الدرس عن الحسابات البنكية حاسبني عليها :D ... هل تظن اني فاهم ماذا تعني ضمان مالي والحاجيات الأخرى ..

سأقوم بالتعديلات .. 11:05 PM

_____________________________

انتهيت كما يبدو ! 12:23

الملفات في المرفقات .. كي لا نفسد التشويق :)

Serialization.rar

#5
اقتباس

ظن أنه بالإمكان اعتباره Object ثم اختبار instance ما رأيك ؟

 

 

نعم يُمكن ذلك باستخدام المؤثر instanceof, هكذا :

Object o;
....
if (o instanceof (CompteBank)){
  CompteBank cb = (CompteBank)o; //downcasting
  //do something
} else {
  Client c = (Client) o; //downcasting
  //do something
}

لكن أنا أفضل الطريقة التي ذكرتُها لك.

مواضيع مشابهة