Java'da Serializable ve Externalizable arasındaki fark nedir?


Yanıtlar:


267

Diğer cevaplara eklemek için, uygulayarak java.io.Serializable, sınıfınızdaki nesneler için "otomatik" serileştirme yeteneği elde edersiniz. Başka bir mantık uygulamaya gerek yok, sadece işe yarayacak. Java çalışma zamanı, nesnelerinizi nasıl marshal ve unmarshal yapacağınızı anlamak için yansıma kullanır.

Java'nın önceki sürümlerinde, yansıma çok yavaştı ve bu nedenle büyük nesne grafiklerinin (örneğin, istemci-sunucu RMI uygulamalarında) serileştirilmesi biraz performans sorunuydu. Bu durumla başa çıkmak için, java.io.Externalizableara java.io.Serializablesıra ve sıradan olmayan işlevleri yerine getirmek için özel yazılı mekanizmalara sahip olan arayüz sağlanmıştır ( sınıfınıza uygulamanız readExternalve writeExternalyöntemleriniz gerekir ). Bu size yansıma performansı darboğazını aşmanın yollarını sunar.

Java'nın son sürümlerinde (kesinlikle 1.3), yansıma performansı eskisinden çok daha iyi ve bu yüzden bu çok daha az sorun. ExternalizableModern bir JVM ile anlamlı bir fayda elde etmek için zorlanacağınızdan şüpheleniyorum .

Ayrıca, yerleşik Java serileştirme mekanizması tek değil, JBoss Serialization gibi oldukça hızlı olan ve varsayılan için bir bırakma yedeği olan üçüncü taraf yedekleri alabilirsiniz.

Büyük bir dezavantajı, Externalizablebu mantığı kendiniz tutmanız gerektiğidir - sınıfınıza bir alan ekler, kaldırır veya değiştirirseniz, bunu hesaba katmak için writeExternal/ readExternalyöntemlerinizi değiştirmeniz gerekir.

Özetle, ExternalizableJava 1.1 gününün bir kalıntısıdır. Artık buna gerçekten gerek yok.


61
Bu ölçütlere göre değil: [ code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking] , manuel serileştirme (externizable kullanarak), java'nın varsayılan serileştirmesini kullanmaktan çok, çok daha hızlıdır. Hız işiniz için önemliyse, kesinlikle kendi serileştiricinizi yazın.
volni

6
@Jack
noquery

3
"Java-manuel" in github.com/eishay/jvm-serializers/wiki yok değil ObjectOutputStream kullanarak ima hangi, Externalizable kullanın. Kodun bağlantısı için github.com/eishay/jvm-serializers/wiki/ToolBehavior adresine bakın . Bunun yerine, DataOutputStream kullanan elle yazılmış bir koddur, bu nedenle ObjectOutputStream'i yavaşlatan şeylerden (nesne örneklerini takip etmek ve nesne döngülerini desteklemek gibi) muzdarip değildir.
Esko Luontola

7
Eğer sınıf asla değişmezse ve eski verilerin kalıcı versiyonlarında okumak zorunda kalmazsanız, mantığı kendiniz korumak zorunda kalmak sadece bir dezavantajdır. Eğer eski sürümlerinin serisini kaldırmak için cehennemi kod yazmak zorunda kalmadan sınıfınızı değiştirme özgürlüğü istiyorsanız, çokExternalizable yardımcı olur .
Tim Boudreau

2
Sadece özel bir koleksiyon yazmak zorunda kaldım ve Externalizableboş alanlara veya yer tutucu nesnelere sahip diziler çıkarmak istemediğimden, bana çok daha uygun olduğunu söylemeliyim , ayrıca açık arabirimle mirasımı işleyebilirsin, yani senkronize edilmiş altım -class kolayca çağrı etrafında kilitleme ekleyebilirsiniz writeExternal(). Yani evet, Dışsallaştırılabilir, kesinlikle büyük veya karmaşık nesneler için hala çok alakalı.
Haravikk

37

Serileştirme, nesneyi depolamak ve daha sonra yeniden oluşturmak için varsayılan işlevsellik sağlar. Depolanacak nesnelerin tüm grafiğini tanımlamak için ayrıntılı format kullanır, örneğin bir LinkedList'iniz olduğunu ve aşağıdaki gibi kodladığınızı varsayalım, o zaman varsayılan serileştirme, bağlantılı ve serileştirilecek tüm nesneleri keşfedecektir. Varsayılan serileştirmede nesne, yapıcı çağrısı olmadan tamamen depolanmış bitlerinden oluşturulur.

  ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("/Users/Desktop/files/temp.txt"));
        oos.writeObject(linkedListHead); //writing head of linked list
        oos.close();

Ancak kısıtlı serileştirme yapmak veya nesnenizin bir bölümünün serileştirilmesini istemiyorsanız Externalizable'ı kullanın. Externalizable arabirimi Serializable arabirimini genişletir ve iki yöntem ekler: writeExternal () ve readExternal (). Bunlar serileştirme veya serileştirme sırasında otomatik olarak çağrılır. Externalizable ile çalışırken, varsayılan kurucunun herkese açık olması gerektiğini unutmamalıyız, aksi takdirde kod istisna atar. Lütfen aşağıdaki kodu takip edin:

public class MyExternalizable implements Externalizable
{

private String userName;
private String passWord;
private Integer roll;

public MyExternalizable()
{

}

public MyExternalizable(String userName, String passWord, Integer roll)
{
    this.userName = userName;
    this.passWord = passWord;
    this.roll = roll;
}

@Override
public void writeExternal(ObjectOutput oo) throws IOException 
{
    oo.writeObject(userName);
    oo.writeObject(roll);
}

@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException 
{
    userName = (String)oi.readObject();
    roll = (Integer)oi.readObject();
}

public String toString()
{
    StringBuilder b = new StringBuilder();
    b.append("userName: ");
    b.append(userName);
    b.append("  passWord: ");
    b.append(passWord);
    b.append("  roll: ");
    b.append(roll);

    return b.toString();
}
public static void main(String[] args)
{
    try
    {
        MyExternalizable m  = new MyExternalizable("nikki", "student001", 20);
        System.out.println(m.toString());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
        oos.writeObject(m);
        oos.close();

        System.out.println("***********************************************************************");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
        MyExternalizable mm = (MyExternalizable)ois.readObject();
        mm.toString();
        System.out.println(mm.toString());
    } 
    catch (ClassNotFoundException ex) 
    {
        Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch(IOException ex)
    {
        Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
    }
}
}

Burada varsayılan yapıcıya yorum yaparsanız, kod istisnanın altına atılacaktır:

 java.io.InvalidClassException: javaserialization.MyExternalizable;     
 javaserialization.MyExternalizable; no valid constructor.

Parola hassas bilgi olarak gözlemleyebiliriz, bu yüzden writeExternal (ObjectOutput oo) yönteminde seri hale getirmiyorum ve readExternal (ObjectInput oi) içinde aynı değeri ayarlamıyorum. Externalizable tarafından sağlanan esneklik budur.

Yukarıdaki kodun çıktısı aşağıdaki gibidir:

userName: nikki  passWord: student001  roll: 20
***********************************************************************
userName: nikki  passWord: null  roll: 20

PassWord'un değerini ayarlamadığımız için gözlemleyebiliriz, bu yüzden null.

Aynı şey, şifre alanının geçici olarak bildirilmesiyle de elde edilebilir.

private transient String passWord;

Umarım yardımcı olur. Herhangi bir hata yaptıysam özür dilerim. Teşekkürler.


22

SerializableVe arasındaki temel farklarExternalizable

  1. Marker arayüzü : Serializableherhangi bir yöntem olmadan marker arayüzüdür. Externalizablearayüz iki yöntem içerir: writeExternal()ve readExternal().
  2. Serileştirme süreci : SerializableArayüzü uygulayan sınıflar için varsayılan Serileştirme süreci başlatılacaktır . Programcı tanımlı serileştirme süreci Externalizablearabirimi uygulayan sınıflar için devreye girecektir.
  3. Bakım : Uyumsuz değişiklikler serileştirmeyi bozabilir.
  4. Geriye Dönük Uyumluluk ve Kontrol : Birden fazla sürümü desteklemeniz gerekiyorsa, Externalizablearabirim ile tam kontrole sahip olabilirsiniz . Nesnenizin farklı sürümlerini destekleyebilirsiniz. Eğer uygularsanız Externalizable, bu serialize sizin sorumluluğunuzdur supersınıfın
  5. public No-arg yapıcısı : Serializablenesneyi oluşturmak için yansıma kullanır ve arg yapıcısı gerektirmez. Ancak Externalizablekamuya tartışmasız yapıcı talep ediyor.

Bakınız blog tarafından Hitesh Gargdaha fazla ayrıntı için.


1
(3) yanlış. Mevcut nesnelerin serileştirmesini bozmadan bir sınıfa yapabileceğiniz büyük bir değişiklik repertuvarı var ve serileştirilebilir üyeler eklemek kesinlikle bunlardan biri. Bunları silmek başka bir şeydir. Java Object Serialization Specification'ın Nesne Sürümlemesi bölümüne bakın .
Lorne Marquis

1
Yeniden ifade edilen cümle.
Ravindra babu

Serialization spesifikasyonunun bağlantısını paylaştığınız için teşekkür ederiz.
JL_SO

21

Serileştirme, nesneyi depolamak ve daha sonra yeniden oluşturmak için belirli varsayılan davranışları kullanır. Referansları ve karmaşık veri yapılarını hangi sırada veya nasıl işleyeceğinizi belirtebilirsiniz, ancak sonunda her ilkel veri alanı için varsayılan davranışı kullanmaya gelir.

Haricilaştırma, nesnenizi tamamen farklı bir şekilde depolamak ve yeniden oluşturmak istediğiniz nadir durumlarda ve veri alanları için varsayılan serileştirme mekanizmalarını kullanmadan kullanılır. Örneğin, kendi benzersiz kodlama ve sıkıştırma düzeninize sahip olduğunuzu düşünün.


5
"Seçili kimliklerin" büyük koleksiyonları için Haricileştirilebilir'i kullandık - varsayılan serileştirmeden çok az ya da çok bir sayı ve bir dizi ilkel giriş olarak dışsallaştırmak çok daha etkili oldu. Bu çok basit bir kullanıcı tabanı, "özel" veya "benzersiz" hiçbir şey.
Thomas W

9

Nesne Dizileştirme, Serileştirilebilir ve Dışsallaştırılabilir arabirimleri kullanır. Bir Java nesnesi yalnızca serileştirilebilir. bir sınıf veya üst sınıflarından herhangi biri java.io.Serializable arabirimini veya alt arabirimini java.io.Externalizable uygularsa. Java sınıfının çoğu serileştirilebilir .

  • NotSerializableException: packageName.ClassName«Bir Sınıf Nesnesini serileştirme sürecine katılmak için, sınıfın Seri veya Harici olarak kullanılabilen arabirim uygulaması gerekir.

resim açıklamasını buraya girin


Serileştirilebilir Arayüz

Nesne Dizileştirme, kaydedilmekte olan nesneler için Java sınıfları hakkında bilgi içeren bir akış oluşturur. Serileştirilebilir nesneler için, sınıfın uygulanmasının farklı (ancak uyumlu) bir sürümü mevcut olsa bile bu nesneleri geri yüklemek için yeterli bilgi tutulur. Serileştirilebilir arayüz, serileştirilebilir protokolü uygulayan sınıfları tanımlamak için tanımlanmıştır:

package java.io;

public interface Serializable {};
  • Serileştirme arayüzünde herhangi bir yöntem veya alan yoktur ve sadece serileştirilebilir olmanın anlambilimini tanımlamaya yarar. Bir sınıfı serileştirmek / serisini kaldırmak için ya varsayılan writeObject ve readObject yöntemlerini kullanabiliriz (ya da) bir sınıftan writeObject ve readObject yöntemlerini geçersiz kılabiliriz.
  • JVM, nesnenin serileştirilmesinde tam kontrole sahip olacaktır. kullanmak geçici anahtar kelime dizgeleştirme veri üyesini önlemek için.
  • Burada serileştirilebilir nesneler yürütmeden doğrudan akıştan yeniden oluşturulur
  • InvalidClassException« Serisini kaldırma işleminde, yerel sınıf serialVersionUID değeri karşılık gelen gönderenin sınıfından farklıysa . sonuç şu şekilde çelişkilidir: java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
  • Sınıfın geçici ve statik olmayan alanlarının değerleri serileştirilir.

Haricilaştırılabilir Arayüz

Haricilaştırılabilir nesneler için, yalnızca nesne sınıfının kimliği kapsayıcı tarafından kaydedilir; sınıf içeriği kaydetmeli ve geri yüklemelidir. Haricilaştırılabilir arayüz aşağıdaki gibi tanımlanır:

package java.io;

public interface Externalizable extends Serializable
{
    public void writeExternal(ObjectOutput out)
        throws IOException;

    public void readExternal(ObjectInput in)
        throws IOException, java.lang.ClassNotFoundException;
}
  • Externalizable arabiriminin iki yöntemi vardır; haricileştirilebilir bir nesnenin, bir nesnenin durumunu kaydetmek / geri yüklemek için bir writeExternal ve readExternal yöntemleri uygulaması gerekir.
  • Programcı hangi nesnelerin serileştirileceğine dikkat etmelidir. Bir programcı Seri Hale Getirme olarak Bu nedenle, burada geçici anahtar kelime Serileştirme sürecinde herhangi bir nesneyi kısıtlamayacaktır.
  • Haricilaştırılabilir bir nesne yeniden oluşturulduğunda, genel no-arg yapıcısı kullanılarak bir örnek oluşturulur ve daha sonra readExternal yöntemi çağrılır. Serileştirilebilir nesneler bir ObjectInputStream öğesinden okunarak geri yüklenir.
  • OptionalDataException« Yazdığımız gibi alanlar AYNI SİPARİŞ VE TÜRDE OLMALIDIR . Akıştan herhangi bir tür uyuşmazlığı varsa OptionalDataException öğesini atar.

    @Override public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt( id );
        out.writeUTF( role );
        out.writeObject(address);
    }
    @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.id = in.readInt();
        this.address = (Address) in.readObject();
        this.role = in.readUTF();
    }
  • Serileştirilmek için yazılan (pozlanan) sınıfın örnek alanları ObjectOutput.


Örnek « Serializable uygular

class Role {
    String role;
}
class User extends Role implements Serializable {

    private static final long serialVersionUID = 5081877L;
    Integer id;
    Address address;

    public User() {
        System.out.println("Default Constructor get executed.");
    }
    public User( String role ) {
        this.role = role;
        System.out.println("Parametarised Constructor.");
    }
}

class Address implements Serializable {

    private static final long serialVersionUID = 5081877L;
    String country;
}

Örnek «, Haricilaştırılabilir

class User extends Role implements Externalizable {

    Integer id;
    Address address;
    // mandatory public no-arg constructor
    public User() {
        System.out.println("Default Constructor get executed.");
    }
    public User( String role ) {
        this.role = role;
        System.out.println("Parametarised Constructor.");
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt( id );
        out.writeUTF( role );
        out.writeObject(address);
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.id = in.readInt();
        this.address = (Address) in.readObject();
        this.role = in.readUTF();
    }
}

Misal

public class CustomClass_Serialization {
    static String serFilename = "D:/serializable_CustomClass.ser";

    public static void main(String[] args) throws IOException {
        Address add = new Address();
        add.country = "IND";

        User obj = new User("SE");
        obj.id = 7;
        obj.address = add;

        // Serialization
        objects_serialize(obj, serFilename);
        objects_deserialize(obj, serFilename);

        // Externalization
        objects_WriteRead_External(obj, serFilename);
    }

    public static void objects_serialize( User obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        // java.io.NotSerializableException: com.github.objects.Address
        objectOut.writeObject( obj );
        objectOut.flush();
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");
    }
    public static void objects_deserialize( User obj, String serFilename ) throws IOException{
        try {
            FileInputStream fis = new FileInputStream( new File( serFilename ) );
            ObjectInputStream ois = new ObjectInputStream( fis );
            Object readObject;
            readObject = ois.readObject();
            String calssName = readObject.getClass().getName();
            System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException

            User user = (User) readObject;
            System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);

            Address add = (Address) user.address;
            System.out.println("Inner Obj : "+ add.country );
            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File( serFilename ));
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        obj.writeExternal( objectOut );
        objectOut.flush();

        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            // create a new instance and read the assign the contents from stream.
            User user = new User();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            user.readExternal(ois);

            System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);

            Address add = (Address) user.address;
            System.out.println("Inner Obj : "+ add.country );
            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

@görmek


7

Dışsallaştırılabilir arayüz, serileştirme işlemi performansını optimize etmek için gerçekte sağlanmadı! ancak kendi özel işlemlerinizi gerçekleştirmenin yollarını sağlamak ve bir nesne ve onun süper türleri için akışın biçimi ve içeriği üzerinde tam kontrol sağlamak!

Bunun örnekleri, yerel eylem komut dosyası nesnelerini ağ üzerinden aktarmak için AMF (ActionScript İleti Biçimi) uzaktan uygulamasının uygulanmasıdır.


7

https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html

Varsayılan serileştirme biraz ayrıntılıdır ve serileştirilmiş nesnenin mümkün olan en geniş kullanım senaryosunu varsayar ve buna göre varsayılan biçim (Serileştirilebilir), serileştirilmiş nesnenin sınıfı hakkında bilgi ile sonuç akışına açıklama ekler.

Dışsallaştırma, nesne akışı üreticisine, sınıfın gerekli minimum tanımlamasının (örneğin adı) kesin sınıf meta verileri (varsa) üzerinde tam kontrol sağlar. Bu, nesne akışı üreticisi ve tüketicisinin (nesneyi akıştan ayıran) eşleştiği ve sınıf hakkındaki ek meta verilerin hiçbir amaca hizmet etmediği ve performansı düşürdüğü kapalı ortamlar gibi belirli durumlarda açıkça istenir.

Ek olarak (Uri'nin işaret ettiği gibi) haricilaştırma, Java türlerine karşılık gelen akıştaki verilerin kodlanması üzerinde tam kontrol sağlar. (Tutarlı) bir örnek için, boole true değerini 'Y' ve false 'N' olarak kaydetmek isteyebilirsiniz. Dışsallaştırma bunu yapmanızı sağlar.


2

Performansı artırma seçeneklerini göz önünde bulundururken, özel serileştirmeyi unutmayın. Java'nın iyi veya en azından yeterince iyi bir şekilde ücretsiz yapmasına izin verebilir ve kötü bir şekilde yaptığı şey için özel destek sağlayabilirsiniz. Bu genellikle tam Haricileştirilebilir desteğe göre çok daha az koddur.


2

Serializable ve Externalizable arasında çok fazla fark var, ancak özel Serializable (geçersiz kılınan writeObject () & readObject ()) ve Externalizable arasındaki farkı karşılaştırdığımızda, özel uygulamanın ObjectOutputStream sınıfı ile sıkı bir şekilde bağlandığını görüyoruz. ObjectOutputStream sınıfı olabilecek ya da org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream gibi başka bir nesne olabilen bir ObjectOutput uygulaması sağlayın

Haricilaştırılabilir arayüz durumunda

@Override
public void writeExternal(ObjectOutput out) throws IOException {
    out.writeUTF(key);
    out.writeUTF(value);
    out.writeObject(emp);
}

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    this.key = in.readUTF();
    this.value = in.readUTF();
    this.emp = (Employee) in.readObject();
}





**In case of Serializable interface**


        /* 
             We can comment below two method and use default serialization process as well
             Sequence of class attributes in read and write methods MUST BE same.
        // below will not work it will not work . 
        // Exception = java.io.StreamCorruptedException: invalid type code: 00\
              private void writeObject(java.io.ObjectOutput stream) 
              */
            private void writeObject(java.io.ObjectOutputStream Outstream)
                    throws IOException {

                System.out.println("from writeObject()");
                /*     We can define custom validation or business rules inside read/write methods.
 This way our validation methods will be automatically 
    called by JVM, immediately after default serialization 
    and deserialization process 
    happens.
                 checkTestInfo();
                */

                stream.writeUTF(name);
                stream.writeInt(age);
                stream.writeObject(salary);
                stream.writeObject(address);
            }

            private void readObject(java.io.ObjectInputStream Instream)
                    throws IOException, ClassNotFoundException {
                System.out.println("from readObject()");
                name = (String) stream.readUTF();
                age = stream.readInt();
                salary = (BigDecimal) stream.readObject();
                address = (Address) stream.readObject();
                // validateTestInfo();
            }

Daha iyi açıklamak için örnek kod ekledim. Lütfen Haricileştirilebilir nesne giriş / çıkış nesnesini kontrol edin. Bunlar doğrudan herhangi bir uygulamaya bağlı değildir.
Outstream / Instream olarak sınıflara sıkıca bağlanır. ObjectOutputStream / ObjectInputStream öğesini genişletebiliriz, ancak kullanımı biraz zor olacaktır.


1
Daha fazla ayrıntı verebilir misiniz? Okurken, ne söylemeye çalıştığınızı anlamıyorum. Ayrıca, metni bazı paragraflar ve örneklerle biçimlendirebilirseniz, bu harika bir yanıt olabilir.
Shirkam

0

Temel olarak, Serializablebir sınıfın serileştirme için güvenli olduğunu ve JVM'nin serileştirileceğini nasıl belirlediğini gösteren bir işaretleyici arabirimidir. Externalizable2 yöntem içerir readExternalve writeExternal. Externalizablegibi bir nesne seri hale nasıl karar uygulayıcısı, izin verir Serializableserializes varsayılan yolu nesneleri.


0

Bazı farklılıklar:

  1. Serileştirme için, bu sınıfın varsayılan yapıcısına gerek yoktur çünkü Object JVM, Reflection API'sinin yardımıyla aynı şeyi yapılandırır. Herhangi bir arg olmayan dışsallaştırma yapıcısı gerektiğinde, kontrol programmar'ın elindedir ve daha sonra, serileştirilmiş verileri ayarlayıcılar aracılığıyla nesneye atar.

  2. Serileştirmede, kullanıcı serileştirilecek belirli özellikleri atlamak istiyorsa, bu özellikleri geçici olarak işaretlemek zorundaysa, Haricilaştırma için bunun tersi gerekli değildir.

  3. Herhangi bir sınıf için geriye dönük uyumluluk desteği beklendiğinde, Dışsallaştırılabilir ile devam etmeniz önerilir. Serileştirme defaultObject sürekliliğini destekler ve nesne yapısı bozulursa, serileştirmeyi kaldırırken soruna neden olur.

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.