I have a base class named Train:
public abstract class Train {
String serialNo;
float weight;
final String label;
public Train(String serialNo, float weight, String label) {
this.serialNo = serialNo;
this.weight = weight;
this.label = label;
}
public abstract float getCapacity();
}
And I have 2 classes implementing the abstract class(I will not include getters and setters in the code):
public class FreightTrain extends Train implements Cloneable {
private float capacityKg;
Vector<String> freightVector = new Vector<String>();
public FreightTrain(String serialNo, float weight, String label) throws Exception{
super(serialNo, weight, label);
if (weight < 0)
throw new Exception();
}
#Override
public float getCapacity() {
return this.capacityKg;
}
}
And the PassengerTrain class:
public class PassengerTrain extends Train implements Cloneable {
private float seatNo;
Vector<String> passengerId = new Vector<String>();
public PassengerTrain(String serialNo, float weight, String label) throws Exception{
super(serialNo, weight, label);
if (weight < 0)
throw new Exception();
}
#Override
public float getCapacity() {
return this.seatNo;
}
}
Next I have an array list ArrayList<Train> arr; which contains both: the PassengerTrain and FreightTrain. I want to create methods to write the items from arr to a file and read the data from file
Here is my attempt:
public void writeObjectInTextFile(ArrayList<Train> array) {
Formatter f = null;
try {
f = new Formatter(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
for(Train train: array) {
if(train instanceof PassengerTrain) {
String label = train.getLabel();
String serialNo = train.getSerialNo();
float capacity = train.getCapacity();
float weight = train.getWeight();
float seatNo = ((PassengerTrain) train).getSeatNo();
String passId = "";
for(String id:((PassengerTrain) train).getPassengerId()) {
passId += id;
}
f.format("%s %f %s %f %f %s", serialNo, weight, label, capacity, seatNo, passId);
} else if(train instanceof FreightTrain) {
String label = train.getLabel();
String serialNo = train.getSerialNo();
float capacity = train.getCapacity();
float weight = train.getWeight();
float capacityKg = ((FreightTrain) train).getCapacityKg();
String freightVector = "";
for(String freight: ((FreightTrain) train).getFreightVector()) {
freightVector += freight;
}
f.format("%s %f %s %f %f %s", serialNo, weight, label, capacityKg, capacity, freightVector);
}
}
f.close();
}
But I have a problem: I am unable to create a function that will read this data from the file, and return the correct ArrayList with the initial data.
What is the best and fastest way to write the array of 2 different classes deriving from a single class to a file?
And how it could be recreated?
Thank you!
Please don't my question as duplicate. I have searched for similar questions and my question is different from the ones available.
I don't know how to convert back the objects from file to their respective types. What If I have n deriving classes?
Simply have your classes implement Serializable and you'll be ready to write your objects to files (and read them back, of course) whenever you want! This includes arrays of your objects, too.
That's the 10000-foot answer above. Implementing Serializable correctly (in a way that won't come back around to bite you) is a somewhat daunting subject. However, there is plenty of literature out there that can teach you how to do it and how to avoid common pitfalls. I recommend Joshua Bloch's "Effective Java" for this, personally; he's dedicated a whole chapter or two to the subject.
if(train instanceof PassengerTrain) This is bad. You are completely throwing the whole purpose of inheritance and polymorphism away. Your code shouldn't care about what type the trains are.
You should use the Object serialization features of Java. Implement Serializable in your Train class and use ObjectOutputStream to write and ObjectInputStream to read the objects.
Write:
public void writeTrainsToFile(ArrayList<Train> array, String file) {
FileOutputStream fileOutputStream = new FileOutputStream(file);
try(ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)){
objectOutputStream.writeInt(array.size());
for(Train train: array) {
objectOutputStream.writeObject(train);
}
}
}
Read:
public void readTrainsFromFile(ArrayList<Train> array, String file) {
FileInputStream fileInputStream = new FileInputStream(file);
try(ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)){
int trainCount = objectInputStream.readInt();
for (int i = 0; i < trainCount; i++) {
array.add((Train)objectInputStream.readObject());
}
}
}
Related
I have an assignment where I have to read a data file containing student names and their GPAs, and put it into a linked list in ascending order. I've been struggling with the Linked List conceptually, and I've gotten to a point where I'm utterly lost. I'm not quite sure how to put the information I'm getting off of the file into a linked list. We can't use any of the built-in collection classes either, which makes it a bit more difficult.
public class Driver {
private LinkedList<Student> myList;
String name;
double doub;
public static void main(String[] args) {
new Driver();
}
public Driver() {
myList = new LinkedList<Student>();
FileInputStream file;
Student x = new Student(name, doub);
int count = 0;
try {
file = new FileInputStream("Student.dat");
BufferedReader read = new BufferedReader(new InputStreamReader(file));
String lineRead;
while ((lineRead = read.readLine()) != null) {
count++;
x = new Student(lineRead,count);
} catch (IOException e) {
e.printStackTrace();
}
I also have the "Student" class here.
public class Student<E> {
private String name;
private double gpa;
private E value;
private Student nextNode;
public Student(String name, double gpa) {
this.name = name;
this.gpa = gpa;
}
public Student(E x) {
value = x;
}
public Student getNext() {
return nextNode;
}
public E getValue() {
return value;
}
public void setValue(E x) {
value = x;
}
public void setNext(Student next) {
nextNode = next;
}
public String getName() {
return this.name;
}
public double getGPA() {
return this.gpa;
}
The data file also reads as
Emily 2.5
Evan 3.8
Lily 4.0
April 1.9
I've done some testing to try and figure out what is going on, mostly just adding methods to see what they put out and working it from there. For example I know that, If I were to put run "System.out.println(x.getGPA());" in the try catch, it would return the following
1.0
2.0
3.0
4.0
Which makes sense because I'm assuming its just reading the count instead of the numbers in the data file. If I were to run "Sysetm.out.println(x.getName());" in the try catch, it would return the following
Emily 2.5
Evan 3.8
Lily 4.0
April 1.9
This is almost correct, but If I run something like "System.out.println(myList);" I would just get
LinkedList#7852e922
LinkedList#7852e922
LinkedList#7852e922
LinkedList#7852e922
And I am 90% sure those are all null. Moving forward from that running "System.out.println(x);" returns this
Student#7852e922
Student#4e25154f
Student#70dea4e
Student#5c647e05
I think I've completely overthought this problem. There are a few other parts to the assignment, but I think if I can at least get this working I'll be set to move forward.
As the title suggest, how do I do that? I have searched everywhere in the internet, maybe I didn't search for the right word or something. But please help me.
Object[] FlyingObject = new FlyingObject[3];
FlyingObject[0] = new Helicopter();
FlyingObject[1] = new Airplane();
FlyingObject[2] = new Drone();
Public static Object[] CopyFlyingObject(Object[] C){
Object FlyingObjectCopy = new Object(C.length);
// ...I got no idea how to continue from here
}
Using clone() is not allowed and you aren't allowed to find the name of the class either. I have copy constructor in my other classes but I have no idea how to call it when we're using object, especially with an object array with unknown classes throughout the array.
Edit:
My Subclass code
'''java
int speed;
double price;
Helicopter(){
speed = 0;
price = 0.0;
}
Helicopter(Helicopter c){
speed = c.speed;
price = c.price;
}
public Airplane extends Helicopter{
String brand;
Airplane(){
super();
brand = "";
}
Airplane(Airplane c){
super(C);
brand = c.brand;
}
public String getBrand(){
return brand;
}
}
public Drone{
//practically the same for here
}
'''
In my Android application, I have a list of custom objects
ArrayList<Poke> pcList = new ArrayList<>();
Later in my code, I have save and load methods, that use Java OOS, and OIS to function. I have used these exact methods in other projects and know they work properly.
I believe I am having an issue with saving and loading a list of custom objects.
Here are the lines I'm calling to save, as well as load my list.
// save
oos.writeObject(pcList);
...
// load
pcList = (ArrayList<Poke>)ois.readObject();
Any ideas why I can't properly load/save with my list of custom objects?
Here is the interface that links a few similar objects:
public interface Poke {
int getNum();
String getName();
String getType();
int getValue();
boolean getShiny();
String getImageName();
}
Here is one of the similar object classes
public class BasicPoke implements Poke {
boolean shiny = false;
Random randomInt = new Random();
int iRandom = randomInt.nextInt(34 - 1) + 1;
int iShiny = randomInt.nextInt(31 - 1) + 1;
public int getNum(){
return this.iRandom;
}
public String getName(){
return this.pokeNames[iRandom-1];
}
public String getType(){
return this.pokeTypes[iRandom-1];
}
public int getValue(){
return 1;
}
public boolean getShiny() {
return (iShiny == 15);
}
public String getImageName() {
String threeDigitInteger = String.format(Locale.getDefault(),"%03d", this.getNum());
return (this.getShiny()) ? "icon"+threeDigitInteger+"s" : "icon"+threeDigitInteger;
}
String pokeNames = {"..","..",".."};
String pokeTypes = {"..","..",".."};
Please implement Serializable for the BasicPoke class. And by the way, could you tell us what issue (exception) when you load/save a list of objects?
Thanks,
Nghia
I was wondering if there was an easy way to save arrays of objects, without having to go through and save each aspect of the the objects. In my example I have two arrays, one a single array and the other a 2D array, that contain objects referring to a custom class. Each object has specific details like x and y ints, booleans, strings, ect. attached to them (block[0].x, block[0].canWalk, block[0].name) and I was wondering if there is an easy way of saving these arrays to a file without having to use a for loop and save each part. The multidimensional array is simply an array of saved arrays identical to the first one (savedBlock[0][0].x ...)
What I have so far (throwing NotSerializableException):
public class Save
{
static File f;
static ObjectOutputStream os;
public static void openFile()
{
try
{
if(!new File("c:\\IDsGame").exists())
{
new File("c:\\IDsGame").mkdirs();
}
f = new File("c:\\IDsGame\\data.bin");
os = new ObjectOutputStream(new FileOutputStream(f));
writeFile();
}
catch(Exception e)
{
System.err.println("creating file");
}
}
public static void writeFile()
{
try
{
ArrayList<Object> map = new ArrayList<Object>(Arrays.asList(Map.block));
ArrayList<Object> savedMaps = new ArrayList<Object>(Arrays.asList(Map.savedMaps));
os.writeObject(map);
os.writeObject(savedMaps);
os.close();
}
catch (IOException e) {System.out.println(e);}
}
}
Within my map class I initialize block (Blocks[]) and savedMaps(Blocks[][]). My Blocks class holds this:
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public Image img = null, imgBack = null;
public final Image (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Obviously I change the certain parts different arrays within the Map class, and I was wondering if there was any easier way (at all) to save the arrays of Blocks Objects.
Thanks for taking your time to help and if you need any more specific just let me know.
I.D.
Image is not serializable, so you receive a NotSerializableException when the Blocks class is serialized. ImageIcon can be serialized, so wrapping Image instances in ImageIcons will solve that issue.
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public ImageIcon img = null, imgBack = null;
public final ImageIcon (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
// img = new ImageIcon(someImageInstance)
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Just making a class implement Serializable is not enough: All the fields must be Serializable too.
Your Block class may have a problem. All the usual java classes are Serializable, but Block also has fields of type Image. If Image isn't Serializable, then attempting to serialize Block will throw NotSerializableException.
How can I sort a vector of my custom object and choose which property to sort by?
I did see this question & answer but I'm not too sure what its sorting it based on. Code example would be prefered to "methodology".
Sort a Vector of custom objects
public class ItemLocation {
String icon;
String title;
String message;
String subtext;
String deviceId;
double latCoords;
double lngCoords;
int expiary;
int id;
double proximity;
String locSeen;
}
Below is a example that will allow you to sort by a specified field of ItemLocation:
public void sort(final String field, List<ItemLocation> itemLocationList) {
Collections.sort(itemLocationList, new Comparator<ItemLocation>() {
#Override
public int compare(ItemLocation o1, ItemLocation o2) {
if(field.equals("icon")) {
return o1.icon.compareTo(o2.icon);
} if(field.equals("title")) {
return o1.title.compareTo(o2.title);
} else if(field.equals("message")) {
return o1.message.compareTo(o2.message);
}
.
. fill in the rest of the fields...
.
else if(field.equals("locSeen")) {
return o1.locSeen.compareTo(o2.locSeen);
}
}
});
}
See the JavaDocs for java.util.Comparable and java.util.Comparator.
A class that implements Comparable can be compared against other instances of that class. This is useful to implement a natural search order. To allow ordering other than the class's natural order you would need to implement a Comparator. A Comparator is a separate object that is capable of comparing two other objects using whatever criteria it wants.
In your case you'd probably want to implement a Comparator for each of the different properties that you want to order by, or one that can be configured.
Comparable and Comparator both use the same idea to determine ordering: A method returns less than 0, 0, or greater than 0 to inform the caller which of the 2 objects is ordered first. In the case of Comparable the first object is this.
This one works:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* ComparableDemo
* #author Michael
* #since 2/24/11
*/
public class ComparableDemo
{
public static void main(String[] args)
{
List<ItemLocation> itemLocations = new ArrayList<ItemLocation>();
for (String arg : args)
{
itemLocations.add(new ItemLocation(arg));
}
System.out.println("before sort: " + itemLocations);
Comparator<ItemLocation> comparator = new ItemLocationComparator();
Collections.sort(itemLocations, comparator);
System.out.println("after sort: " + itemLocations);
}
}
class ItemLocation
{
String icon;
String title;
String message;
String subtext;
String deviceId;
double latCoords;
double lngCoords;
int expiary;
int id;
double proximity;
String locSeen;
ItemLocation(String message)
{
this("", "", message, "", "", 0.0, 0.0, 0, 0, 0.0, "");
}
ItemLocation(String icon, String title, String message, String subtext, String deviceId, double latCoords, double lngCoords, int expiary, int id, double proximity, String locSeen)
{
this.icon = icon;
this.title = title;
this.message = message;
this.subtext = subtext;
this.deviceId = deviceId;
this.latCoords = latCoords;
this.lngCoords = lngCoords;
this.expiary = expiary;
this.id = id;
this.proximity = proximity;
this.locSeen = locSeen;
}
#Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append("ItemLocation");
sb.append("{message='").append(message).append('\'');
sb.append('}');
return sb.toString();
}
}
class ItemLocationComparator implements Comparator<ItemLocation>
{
public int compare(ItemLocation o1, ItemLocation o2)
{
return o1.message.compareTo(o2.message);
}
}
Here's the output:
C:\JDKs\jdk1.6.0_21\bin\java -Didea.launcher.port=7534 "-Didea.launcher.bin.path=C:\Program Files\JetBrains\IntelliJ IDEA 10.0.2\bin" -Dfile.encoding=windows-1252 com.intellij.rt.execution.application.AppMain ComparableDemo zeb meme apple
before sort: [ItemLocation{message='zeb'}, ItemLocation{message='meme'}, ItemLocation{message='apple'}]
after sort: [ItemLocation{message='apple'}, ItemLocation{message='meme'}, ItemLocation{message='zeb'}]
Process finished with exit code 0
Let's say we have a class with an int and a string. I can define how one object of that class may be compared against other.
I could choose any criteria. For instance, I may decide to sort based on the int. If I happen to have two int's with the same value, I may decide the string as an additional criteria, something like this:
// this class *knows* how to "compare" against him self
class CustomObject implements Comparable<CustomObject> {
String aString;
int aInt;
...
public int compareTo(CustomObject two ) {
int diff = this.aInt - two.aInt;//<-- compare ints
if( diff != 0 ) { // they have different int
return diff;
}
return this.aString.compareTo( two.aString );//<-- compare strings...
}
...
}
Here's a complete running demo ...
import java.util.*;
class SortDemo {
public static void main( String ... args ) {
// create a bunch and sort them
List<CustomObject> list = Arrays.asList(
new CustomObject(3, "Blah"),
new CustomObject(30, "Bar"),
new CustomObject(1, "Zzz"),
new CustomObject(1, "Aaa")
);
System.out.println( "before: "+ list );
Collections.sort( list );
System.out.println( "after : "+ list );
}
}
// this class *knows* how to "compare" against him self
class CustomObject implements Comparable<CustomObject> {
String aString;
int aInt;
CustomObject( int i, String s ) {
aInt = i;
aString = s;
}
// comparable interface lets you
// specify "HOW" to compare two
// custom objects
public int compareTo(CustomObject two ) {
// I migth compare them using the int first
// and if they're the same, use the string...
int diff = this.aInt - two.aInt;
if( diff != 0 ) { // they have different int
return diff;
}
// else let the strings compare them selves
return this.aString.compareTo( two.aString );
}
public String toString(){
return "CustomObject[aInt="+aInt+", aString="+aString+"]";
}
}
Here's the output:
before: [CustomObject[aInt=3, aString=Blah], CustomObject[aInt=30, aString=Bar], CustomObject[aInt=1, aString=Zzz], CustomObject[aInt=1, aString=Aaa]]
after : [CustomObject[aInt=1, aString=Aaa], CustomObject[aInt=1, aString=Zzz], CustomObject[aInt=3, aString=Blah], CustomObject[aInt=30, aString=Bar]]
I hope that's clear enough
You can also pass a custom comparator. Let me know if you need a sample of that.