How to create copy of same object with different reference? - java

friends,
i am facing a problem i have phoneContacts list with name and phone numbers in it.
i want to copy it in two different static lists so that i can use it to other activities. i am using following code but it displays me last list references in both while retrieving data
any one guide me how can i take separate copies of these two objects ?
MyContacts.attackContacts = new ArrayList(phoneContacts);
Collections.copy(MyContacts.attackContacts,phoneContacts);
MyContacts.attackContacts.get(0).setType("attack");
MyContacts.medicalContacts = new ArrayList(phoneContacts);
Collections.copy(MyContacts.medicalContacts,phoneContacts);
MyContacts.medicalContacts.get(0).setType("medical");
System.out.println("attack" + MyContacts.attackContacts.get(0).getType() + " medical " + MyContacts.medicalContacts.get(0).getType());
// result "attack medical" "medical medical"
// it should show independent list results like "attack attack" "medical medical"
any help would be appreciated.

In this case you would need to make a deep copy of the list, i.e., a copy that doesn't copy references, but actually copies the object the references are pointing at.
Collections.copy "copies all of the elements from one list into another". As usual with Java however, the elements of a list are not objects but references.
You could solve this by implementing Cloneable (and using .clone()) or by creating a custom "copy constructor" which takes a to-be-copied object as argument, and creates a new object based on the data of that argument. No matter which option you choose, you'll have to iterate over the list and perform the copy on each object.
Here's an example that uses the copy-constructor approach:
MyContacts.medicalContacts = new ArrayList();
for (Contact c: MyContacts.attackContacts)
medicalContacts.add(new Contact(c)); // add a copy of c.
Related question:
What is the difference between a deep copy and a shallow copy?

Coping the list, creates new list object that still refers to the same element objects.
To make a deep copy, your element object must be clonable, have copy constructor, or some other way to duplicate it and you have to do the copy in a loop, one by one.
for (Elem x: list1) {
list2.add(copyOf(x))
}

Pass the object whcih you wants to copy and get the object which you wants ,
private Object copyObject(Object objSource) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(objSource);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
try {
objDest = new ObjectInputStream(bais).readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return objDest;
}
Cast you objDest to Desiered object

Related

Serializable on ArrayList losing some data

I have an ArrayList of Employee objects where Employee class implements Serializable. I am using this code to write lists to a file:
ArrayList<Employee> empList = new ArrayList<>();
FileOutputStream fos = new FileOutputStream("EmpObject.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// write object to file
empList .add(emp1);
empList .add(emp2);
oos.writeObject(empList);
empList .add(emp3);
oos.writeObject(empList);
}
If I try to de-serialize it I am just getting first two objects not the 3rd one. Can anyone please try why is it?
edit1: If I add all elements at once everything is fine but not the way I did first. What is the difference?
ArrayList<Employee> empList = new ArrayList<>();
FileOutputStream fos = new FileOutputStream("EmpObject.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// write object to file
empList .add(emp1);
empList .add(emp2);
empList .add(emp3);
oos.writeObject(empList);
}
After this I have 3 elements
As GhostCat and uaraven already mentioned reset does not what you are expecting it to do and you should have a look at a tutorial on serialization and maybe consider using sth. else if this isn't fitting your use case.
Your code could look as follows if creating a new FileOutputStream:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class SerializationTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String path = "EmpObject.ser";
ArrayList<Employee> empList = new ArrayList<>();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
empList.add(emp1);
empList.add(emp2);
oos.writeObject(empList);
empList.add(emp3);
// Create a new FileOutputStream to override the files content instead of appending the new employee list
oos = new ObjectOutputStream( new FileOutputStream(path));
oos.writeObject(empList);
ObjectInputStream objectinputstream = new ObjectInputStream(new FileInputStream(path));
List<Employee> readCase = (List<Employee>) objectinputstream.readObject();
System.out.println(readCase);
}
}
What happens with your code:
you write the list into the file, with two entries
you reset the stream
you write the list again, with three entries
Thus your file contains two values, yes. Two lists, one with 2, one with 3 entries.
In other words: reset() doesn't reset what has been written to the file! You wrote one list with two entries. You are only resetting the information about stored objects, so that emp1 and emp2 get serialized completely again. Without the call to reset, the JVM would understand that it doesn't need to fully serialize emp1 and emp2 again.
Meaning: by default the JVM compresses the amount of data to transmit. It remembers which objects where already written, and instead of writing them repeatedly, it only writes something like "object X that was serialized earlier on comes again" into the stream.
So: I think you simply do not understand the point of the reset() method. Solution: read a small tutorial, like the one from tutorialspoint.
Edit given the latest comment by the OP:
What you ask for isn't possible in this way. You are writing list objects. That means that all entries of that list at that point get written to the file. The JVM remembers "that list has been written already", so it will not write it again, even when its internal state changed in the meantime.
Basically ObjectOutputStream remembers objects that are written to it. If the same object (by reference) is written again, it is not serialized, but rather a reference to previous serialized data is written to stream. reset() method cleans up internal data structures of ObjectOutputStream and allows you to write the same object again. reset() does not discard data already written to the stream.
If you try to deserialize your stream into two ArrayLists, you'll get one with two elements and one with three elements.
If you remove call to reset() method, then you will get two array lists with two elements (one actually serialized, and another as a reference to the previous serialized instance)

Java Object Serialization issue

I have some input that I add to a serialized object.
Now when I read the serialized object, I want to check if it exists... If not loop till it has a value in it.
How do i modify the deserialization function to handle that.
There is basically a delay in populating my serializable object. So in the meantime if i were to read that object, it is going to be empty. I want to put a check to read only when it has data in it. if not it should wait till it has some data
public String _displayResults(){
String SomeData = "";
try {
FileInputStream fis = new FileInputStream("SomeDataobj");
ObjectInputStream ois = new ObjectInputStream(fis);
SomeData = (String)ois.readObject();
ois.close();
}
catch(Exception e) {
System.out.println("Exception during deserialization: ");
}
return SomeData;
}
What I tried:
added a wait condition for 2 secs for 10 times... Is there a cleaner way.
while ( ois.readObject().toString().equalsIgnoreCase("") && i <10){
Thread.sleep(2000);
i++;
}
Java provides an API called Externalizable, which allows you to customize the (de) serialization. Serialiazable is marker interface and that indicates the object can be wrote to output stream. Externalizable provides two methods readExternal() and writeExternal() where you can override the behavior.
Your question is not so clear about what you want to achieve, so I am not sure if the above information is helpful for you

Deserializing objects and adding it to an array

Now I am creating an address book in Java 1.6. Now how I have it set up is when you add a contact it gets saved into an array. I have no problem writing the array, however when it comes to reading it I dont know how to get every object I previously saved, and load it into the array again.
Just do you know: addbook is my file, it is a txt file. Array is the array I am using to store the objects. The sort I am using is an insertion sort that sorts the contacts by name. If I have not covered other variable names, and stuff like that, I can clarify.
Finally, just for clarification, my question is asking how I can read the array I saved to a file.
Here is my read code:
try {
FileInputStream in = new FileInputStream(addBook);
ObjectInputStream readIn = new ObjectInputStream(in);
array = readIn.readObject();
readIn.close();
Sorts.insertionSort(array);
model.removeAllElements();
for (int i = array.length - 1; i > 0; i--) {
model.addElement(((Book) array[i]).getContact());
}
comboBox.setModel(model);
} catch (Exception e) {
e.printStackTrace();
}
ObjectInputStream.readObject returns an Object. You cannot assign an Object to a Comparable[] without a cast: array = (Comparable[]) readIn.readObject().

Appending Objects to a .txt file [duplicate]

This question already has an answer here:
StreamCorruptedException: invalid type code: AC
(1 answer)
Closed 5 years ago.
I was trying out a program that was given in the exercise at the end of the chapter 'Serialization'.
The program requires me to declare a class Person which encapsulates only two data members of type Name and Address , which are also classes.
Then I have to take a series of names and addresses from the keyboard , create objects and write them to the file.
However , if the FILE ALREADY EXISTS then the objects must be APPENDED to the existing file.
My program runs perfectly for the first time but for the second time , when I try to read back the appended records , I get an Exception
java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1374)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at Trial.main(Trial.java:66)
I did my bit of research on this and found that the StreamHeader can be written ONLY ONCE and appending corrupts it.
What is the way around it ???
The Object Writing Code is:
try(ObjectOutputStream stream = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(filePath,WRITE,CREATE,APPEND)))) {
for(int i = 0;i<name.length;i++) {
Person aPerson = new Person(name[i],address[i]);
System.out.println(aPerson);
stream.writeObject(aPerson);
stream.reset();
aPerson = null;
}
System.out.println("Writing Complete");
Yes, I've had this problem myself before... it is not possible, unfortunately.
What you could do is to place your objects into a List and persist the full list at a time. As the list is an object it can persisted just as easily. I know this is terrible as this require the entire contents to be read into memory, but it is the only way as far as I know.
The other option (which I recommend) is that you use something like JSon to commit your data. GSon works quite well for this purpose. You can then simply marshall and unmarshall your objects which can be committed to a text file. It's very easy to do as a single line of code is required to go either way (object to JSon-string and vice versa).
This works. So debug your program and see why it doesn't. Probably don't call reset()
public class ClassTest {
public static void main(String a[]) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c:/temp/foo.txt"));
oos.writeObject(new Test("foo", "bar"));
oos.writeObject(new Test("baz", "brr"));
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c:/temp/foo.txt"));
System.out.println(ois.readObject());
System.out.println(ois.readObject());
ois.close();
}
}
class Test implements Serializable {
private String fld1;
private String fld2;
public Test(String v1, String v2) {
this.fld1 = v1;
this.fld2 = v2;
}
#Override
public String toString() {
return "Test [fld1=" + fld1 + ", fld2=" + fld2 + "]";
}
}

How do I determine the size of a dynamically allocated structure in Java before writing it to a file?

Say, for example, I have a complex dynamically allocated structure (such as a binary tree) that needs to be written to a file made up of different sections. I would like to first write the size of the structure as a dword followed by the structure itself, however the size of the structure is only known after I have written the structure to the file. It is difficult, in this case, to pre-determine the size of the structure in memory.
Is it best to write the size as 0, then write the structure, then seek back and overwrite the size with the correct value? I don't like that idea, though. Is there a better/proper way to do it?
Just an idea: write the data to a ByteArrayOutputStream, after that, you should be able to call size() to get the actual length in bytes and call toByteArray() to get the byte buffer, that can be written to a file.
Code example
public static void main (String[] args) throws java.lang.Exception {
ArrayList objects = new ArrayList();
objects.add("Hello World");
objects.add(new Double(42.0));
System.out.println(sizeof(objects));
}
public static int sizeof(Serializable object) {
ObjectOutputStream out = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
out = new ObjectOutputStream(baos);
out.writeObject(object);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return baos != null? baos.size() : -1;
}
This just demonstrate a sizeof emulator (which is different from the c implementation, because it calculates the size of a serialized object - the implementation for raw bytes would be slightly different).
Did you looked at Random Access Files yet?
Why do you need to write the size at all? Won't the file be the size of the structure after you have written it?
If you have variable components like arrays or lists, you can write the sizes of those as you write the data. However the total length is redundant and not very useful.
If you really have to, you can write the data to a ByteArrayOutputStream first to get the length. (But I seriously doubt it)
Please refer the below url http://www.javapractices.com/topic/TopicAction.do?Id=83 for calculating size of object .This utility seems worthful for your need.
To measure the size of a particular object containing data, measure JVM memory use before and after building the object.

Categories