I do not understand that why we need transient keyword to prevent serialization of a particular data member. We can also make it static because static data member can not be serialized. Please guide me if I am wrong!
static does not just make a member not serialized; it also means that there is only one copy of that field for the entire class. If you want there to be a copy of that field for each object, but do not want that object to be serialized, you need transient; static will do something completely different.
Making variables static without fully understanding this is a massively common source of bugs for new Java developers.
Related
Being a newbie, I'm trying to understand serialization and I don't get why one would need to reassign static fields after deserialization (as some suggest in order to keep original values) if by definition all objects of the same class have the same values of static parameters. Isn't it true that a new object automatically receives all static parameters of its class? I mean if deserialization nullifies object's static members and we keep the original object wouldn't that mean that there will be two objects of the same class with different values of static parameters? How's that possible or how am I wrong?
EDIT:
It seems that I wasn't clear enough and I'm sorry about that.
When writing my first sentence I was keeping in mind Bruce Eckel's "Thinking in Java" (4th Ed.). I'm not sure if I can attach a few scans of his book without violating copyright but I actually stumbled upon the last example in "Object serialization" chapter (pp.715-718). By means of his io/StoreCADState.java and io/RecoverCADState.java Eckel gets objects of the same class with different static values. He doesn't go deep enough for me into explanation and I feel totally confused.
I know that static members belong to a class not an object. Although I'm not sure now what it means precisely. I used to believe it implied that whenever an object is created a set of static parameters is 'taken' from the class description and 'added' to an object. If this is correct then why they are not 'added' to an object after deserialization when Object instance being cast to a specific class?
Have a look at the Javadoc for static members here. This is what it says:
They are associated with the class, rather than with any object.
As static members are never associated with any object, they are never stored while serializing the object. Also, new object won't automatically receive all static parameters as they have nothing to do with serialization-deserialization of the objects. If you are trying to store static variables with objects then I'd say it's a design flaw. We should rather declare them as non static if we want to persist their values with objects.
Update:
If you want to store non serializable fields with object then you can do so by writing your implementation of readObject() and writeObject() methods. Have a look at the answer of this SO question for example.
How does serialization reconcile static members?
It doesn't.
I don't get why one would need to reassign static fields after deserialization
You don't.
(as some suggest in order to keep original values)
They're wrong.
if by definition all objects of the same class have the same values of static parameters.
Objects don't have values of static parameters at all. The static members are in the class, not in the object.
Isn't it true that a new object automatically receives all static parameters of its class?
No.
I mean if deserialization nullifies object's static members
It doesn't.
and we keep the original object wouldn't that mean that there will be two objects of the same class with different values of static parameters?
No, because it doesn't happen.
How's that possible
It isn't.
or how am I wrong?
Several ways. Serialization does precisely nothing with static members.
EDIT
It seems that I wasn't clear enough and I'm sorry about that.
You were clear enough. You're just fundamentally mistaken about several things.
When writing my first sentence I was keeping in mind Bruce Eckel's "Thinking in Java" (4th Ed.). I'm not sure if I can attach a few scans of his book without violating copyright
You can't (shouldn't) post images of text here, but you can quote a bit of the book under 'fair use' provisions.
but I actually stumbled upon the last example in "Object serialization" chapter (pp.715-718). By means of his io/StoreCADState.java and io/RecoverCADState.java Eckel gets objects of the same class with different static values.
Impossible. You must have misunderstood. Or else he is using different class loaders, which is a complication not mentioned in your question.
He doesn't go deep enough for me into explanation and I feel totally confused. I know that static members belong to a class not an object. Although I'm not sure now what it means precisely. I used to believe it implied that whenever an object is created a set of static parameters is 'taken' from the class description and 'added' to an object.
No. The static data stays where it is, in the class. If there were multiple copies of it, it couldn't possibly work, or be describable as 'static'.
If this is correct
It isn't.
then why they are not 'added' to an object after deserialization
Because Serialization doesn't deal with static objects in any way.
when Object instance being cast to a specific class?
And that process takes place after Serialization, not during it, and doesn't have anything to do with static data either.
Because static members belong to the class, not to the object, they're not serialized or deserialized by default.
A Class with the same name and different values in static members can be only in another namespace (loaded by another ClassLoader).
Read this to understand: How to serialize static data members of a Java class?
Ok, so this question is mostly just related to: is there a better way to do this?
I have a phonebook application, and you can add users to it, delete them, and such, with each person being assigned a distinct ID#. A Person class stores lastIDused as a static class variable. The phonebook class has a vector of Persons.
My workaround thought is this: create a new non-static variable for the Person class, and upon serializing/saving, for the 1st element in the vector only, store the static variable's data into this new variable. Then, when de-serializing, re-set the static variable using the 1st Person's such-variable.
Going back to my original question: is there a better/more-formal/proper way to do this?
A better solution (IMO) would be to make lastIdUsed an instance field of the PhoneBook class. It sounds like you are already serializing an instance of that class ...
FWIW - making lastIdUsed an instance field of Person is just bad object modelling. The field is almost never going to be useful and almost never going to have a valid value. It will only have a valid value in the case of the first serialized Person in a PhoneBook.
First, I would avoid this kind of thing entirely. Static variables aren't serializable for a reason, namely by deserializing something you would invalidate the state of other objects. For example, if your lastUsedId is at 10 and you deserialize an object where it was at 5, it could lead to creating duplicates (6-10).
However, if you are still going to do this, check out the Externalizable interface. It lets you control the serialization and deserialization of an object. Here[1] is a good discussion on it. In the past I've used Externalizable to more tightly control the format of the object being serialized in order to save space. If you really want to, you could serialize a static variable and set it when you deserialize. You could even only set it if it is higher than the value currently in memory. Again, like other commenters I would advise against this approach entirely, but it doesn't hurt to learn this stuff, eh?
[1] What is the difference between Serializable and Externalizable in Java?
In a process of leaning java serialization concept, i was puzzled at one point. In java serialization process, we use 2 keywords to prevent serialization, i.e.., transient and static. If i don't want to save an instance variable, which keyword should i use, both does exactly the same.
Class A implements Serializable{
private static int x;
private transient int y;
private transient static int x;
}
In the above code all the three instance variables are not saved in a process of serialization. Which keyword is apt and recommended to prevent serialization. Why does two keywords have almost the same functionality. What is the recommended way of declaration to prevent serialization. Correct me if I'm wrong, I'm still learning.
The static keyword transforms an instance variable into a static variable. A side-effect is that the field is not serialized anymore... because it's not a field anymore.
A static variable is a variable of the class. An instance variable is a variable of the object, or instance of the class. You can't blindly go from one to the other.
Read the tutorial page about instance and static variables.
The transient keyword is the right keyword to use, of course.
You are confused: static fields are not instance variables, they are class-wide variables. By declaring a field static, the same field is shared among all instances of this class - it is not part of any specific object anymore, which leads to it not being serialized.
To specifically prevent serialization only transient is applicable...
Transient (and in JAXB XmlTransient) signify that the data is ephemeral and not of permanent importance and thus should just be ignored when it comes to matters of persistence.
Static means the value applies that the class level and thus serializing/deserializing it for multiple instances would be unsafe as values would collide.
Well, Let me define serialization once more.
A serialization is a process in which we persist state of an object.
So, is any static variable is part of an object's state ?..No absolutely not. It is the data which is shared among all objects of a class. So obviously, any static variable is not supposed to be serialized with object's state.
let's assume, we are allowed to persist an object's state. later on, if this variable is changed by some other object/class itself, and if we try to de-serialize the object then what value this static variable will hold. There will be a clash.
So if you want to prevent any instance variable from being serialized , do use transient.
when you will de-serialize the object it will be initialized with a default value.
I need to persist several classes with A LOT of static fields (which are arrays filled & modified during the runtime). It would take a lot of effort to convert from static fields to instance vars, so I'd rather go for a quick solution, if any.
So far the path of least resistance is to cook my own writeObject() for each class.
Alternatively, i dont need Serialization as such - any mechanism to store/load an object from persistent storage will do. E.g. XMLDecoder to decompose the bean objects, etc.
You could write a method to use reflection to serialize all static methods. A static method can be marked transient which would normally be redundant, but you could use this to highlight static fields you don't want to serialize. You can call this method from your writeObject() to save you having to do this for every field.
I'd create a new class that gathers all those static fields, lets call it StaticInfoClass. In StaticInfoClass create all the fields non-static. Create a property in the old class that is type of StaticInfoClass. All instances of the your original class will hold a reference to a unique instance of StaticInfoClass, that will contain all the arrays filled and modified during the runtime. If you have threads make sure you make it a bean with synchronized methods to avoid race conditions.
With this approach, in essence, you are implementing static fields without actually using the static modifier. This simple approach should easy a lot your serialization and deserialization problems and most frameworks will handle it very easily.
Also remember that static fields and global state in programs are normally a bad practice, it should be avoided. I tend to not use static if it is not to declare constants or other trivial data structures that definitely do not changed in runtime.
Have not tried this but might work. if your class defines an array of ObjectStreamField objects named serialPersistentFields , then you can explicitly declare the specific fields saved. You can shove any value into it, even the static fields.
private static String lastUser;
private static int maxAge;
private final static ObjectStreamField[]
serialPersistentFields = {
new ObjectStreamField(
"lastUser", String.class),
new ObjectStreamField("maxAge", int.class)
};
Then you will have to implement readObject, to fetch these values and set it for your static variables. So basically this mechanism allows you to marshall/unmarshall fields from anywhere via serialization. You just need to know what to do with them once you read them back. I would still recommend paying the price for moving your statics to member variables.
details : http://java.sun.com/developer/technicalArticles/ALT/serialization/
What happens if i'll try to serialize an attribute which is static?
thanks
From this article:
Tip 1: Handling Static Variables
Java classes often hold some
globally relevant value in a static
class variable. We won't enter into
the long history of the debate over
the propriety of global variables -
let's just say that programmers
continue to find them useful and the
alternatives suggested by purists
aren't always practical.
For static variables that are
initialized when declared,
serialization doesn't present any
special problems. The first time the
class is used, the variable in
question will be set to the correct
value.
Some statics can't be initialized this
way. They may, for instance, be set by
a human during the running time of the
program. Let's say we have a static
variable that turns on debugging
output in a class. This variable can
be set on a server by sending it some
message, perhaps from a monitor
program. We'll also imagine that when
the server gets this message, the
operator wants debugging turned on in
all subsequent uses of the class in
the clients that are connected to that
server.
The programmer is now faced with a
difficulty. When the class in question
arrives at the client, the static
variable's value doesn't come with it.
However, it contains the default
static state that's set when the
class's no-argument constructor is
called by writeObject(). How can the
client programs receive the new
correct value?
The programmer could create another
message type and transmit that to the
client; however, this requires a
proliferation of message types,
marring the simplicity that the use of
serialization can achieve in
messaging. The solution we've come up
with is for the class that needs the
static transmitted to include a
"static transporter" inner class. This
class knows about all the static
variables in its outer class that must
be set. It contains a member variable
for each static variable that must be
serialized. StaticTransporter copies
the statics into its member variables
in the writeObject() method of the
class. The readObject() method
"unwraps" this bundle and transmits
the server's settings for the static
variables to the client. Since it's an
inner class, it'll be able to write to
the outer class's static variables,
regardless of the level of privacy
with which they were declared.
And from another article:
Static or transient data
However, this "ease" is not true in
all cases. As we shall see,
serialization is not so easily applied
to classes with static or transient
data members. Only data associated
with a specific instance of a class is
serialized, therefore static data,
that is, data associated with a class
as opposed to an instance, is not
serialized automatically. To serialize
data stored in a static variable one
must provide class-specific
serialization.
Similarly, some classes may define
data members to use as scratch
variables. Serializing these data
members may be unnecessary. Some
examples of transient data include
runtime statistics or hash table
mapping references. These data should
be marked with the transient modifier
to avoid serialization. Transient, by
definition, is used to designate data
members that the programmer does not
want or need to be serialized. See
Java in a Nutshell, page 174: mouse
position, preferred size, file handles
(machine specific (native code)).
When writing code if something is
declared transient, then this triggers
(to programmer) necessity of the
posibility of special code for
serialization later.
To serialize an object, you create
some sort of OutputStream object and
then wrap it inside an
ObjectOutputStream object. At this
point you only need to call
writeObject() and your object is
magically serialized and sent to the
OutputStream. To reverse the process,
you wrap an InputStream inside an
ObjectInputStream and call
readObject(). What comes back is, as
usual, a handle to an upcast Object,
so you must downcast to set things
straight. If you need to dynamically
query the type of the object, you can
use the getClass method. Specifically
dk.getClass.getName() returns the name
of the class that dk is an instance
of. I.e., this asks the object for the
name of its corresponding class
object. (Hmmm, True, but what about
syntax? I still need to know what it
is to declare it...too bad) (C++ can
do this in one operation (dynamic_cast
(gives null if wrong type)), java can
use instanceof operator to check if it
is what I think (see Core Java, Ch5
Inheritence, Casting section)
Yes, we can defnitely serialise the static variable, but we wont be able to get any purpose of serialisation on the static variables.
Why because the Static variables are not bounded to any objects in scope.
We serialize objects to store them so they can retrieved later for any use.
Only the Transient varibles you cant make them to get serialised.
You can serialize the value of a static variable / attribute. But strictly speaking, you don't serialize a variable or attribute in its own right, whether it is class level, instance level, or local to a method.
Normally the instance level attributes of an object are serialized as part of the parent object; i.e. the object that they are attributes of. If you translate that to class level attributes, then the notional parent is the class. While there is a runtime object that denotes this class (i.e. the java.lang.Class returned by this.getClass()), this object is not serializable. So from that perspective, a class level (static) attribute is not serializable.