Deep Copy of Object Array Instance, Java - java

I have an object made in my main Recipe recipeOne = new Recipe("Pepperoni Pizza");
This object is an instance of this Object Array defined and constructed here!
public class Recipe implements Cloneable{
String Name;
final int INGREDIENT_ARRAY_MAX = 10;
Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];
public Recipe(String name){
Name = name;
}
So I am looking to make a deep copy of this object with the line Recipe ressippi = (Recipe) recipe.clone(); and it sends me here!
public Object clone(){
Recipe cloneRec = new Recipe(Name);
return cloneRec;
}
I know this is currently a shallow copy because the method only passes references, so if I was to attempt a name change on my new Object that was a clone of recipeOne...it would change both of their names. Obviously I do not want that, I'm fairly lost on this, can anyone help?
EDIT:#Rohit Jain
Both my Recipe class as well as my Ingredient class (the objects the recipe array holds) have toString methods and recipes calls on ingredients in order to print it all out in a nice little format. When I call it on my "recipeOne" object (the one called pepperoni pizza) i get "Pepperoni Pizza: 1.0 Pounds of Dough, 8.0 Ounces of Sauce, 10.0 Ounces of Cheese"
Then I proceed to make the object ressippi and set that to the clone of recipeOne, so all good from here...then I change ressippi's name to "Pineapple Pizza" and that prints out fine but it doesnt print the 3 ingredient objects that recipeOne stored, which it is suppose to do!

Add a copy constructor to the recipe class, which creates a new instance of recipe and copies all of the fields from an original recipe.
Recipe.java
public class Recipe implements Cloneable {
String name;
final int INGREDIENT_ARRAY_MAX = 10;
Ingredient[] ingredients = new Ingredient[INGREDIENT_ARRAY_MAX];
public Recipe(String name) {
this.name = name;
}
//Copy Constructor
private Recipe(Recipe recipe){
this.name = recipe.name;
for(int x = 0; x < recipe.ingredients.length; x++){
this.ingredients[x] = recipe.ingredients[x];
}
}
public static Recipe newInstance(Recipe recipe){
return new Recipe(recipe);
}
//Debug Method
public static void printRecipe(Recipe recipe){
System.out.println("Recipe: " + recipe.name);
for(Ingredient i:recipe.ingredients){
if(i != null && i.getName() != null){
System.out.println("Ingredient: " + i.getName());
}
}
}
//Test Method
public static void main(String[] args) {
Recipe recipe = new Recipe("Chicken Soup");
recipe.ingredients[0] = new Ingredient("Chicken");
recipe.ingredients[1] = new Ingredient("Broth");
Recipe copy = new Recipe(recipe);
copy.ingredients[2] = new Ingredient("Rice");
copy.name = "Chicken Rice Soup";
printRecipe(recipe);
printRecipe(copy);
System.out.println(recipe == copy);
System.out.println(recipe.ingredients == copy.ingredients);
}
}
Ingredient.java
public class Ingredient {
private String name;
public Ingredient(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

As you have found out, implementing the Cloneable doesn't actually clone the object. You'll have to implement the clone() method sensibly, and if you want a deep copy, that's what you should implement.
Now, creating a new Recipe object with the same Name attribute is quite OK. And changing the name for the new object afterwards is also quite okay, it won't change the name of the first object as java String's are immutable.
You may want to have a look at the commons-beanutils package, which provides handy code for cloning objects.
Finally, as for "...only passes references..." you should read eg. this and this thread.
Cheers,

Serialize it! Take a look at the deepClone function as exampled here: http://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html
The other replies on Strings being immutable are true of course, but the problem you tried to describe with the String example was just a bad example; complexer objects like the Ingredients array still is copied-by-reference.
Also: change the name of your array so that it doesn't match the class name (=confusing):
Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];

Related

I have problems returning an object from parent ArrayList

I have 4 classes ( I will shorten them for convenience).
public class PoliceStation{
public String name;
ArrayList<Owner> owners = new ArrayList<>();
public boolean addOwner(Owner owner) {
if(findOwnerID(owner)) {
this.owners.add(owner);
System.out.println("Owner "+owner.getName()+" added.");
return true;
}
System.out.println("Owner "+owner.getName()+" with "+owner.getOwnerIDNumber()+" not added.");
return false;
}
and a few more classes for finding owner objects.
And Owner class:
import java.util.ArrayList;
public class Owner {
String name;
String dateOfBirth;
long ownerIDNumber;
String address;
ArrayList<Vehicle> vehicles=new ArrayList<Vehicle>();
ArrayList<Fine> penalties = new ArrayList<Fine>();
public Vehicle findVehicleObject(String plateNum) {
for(int i=0;i<vehicles.size();i++) {
System.out.println(i);
if(vehicles.get(i).getPlateNumber().equalsIgnoreCase(plateNum)) {
System.out.println("Vehicle with that plate number "+plateNum+" exists.");
return vehicles.get(i);
}
}
System.out.println("Vehicle doesnt exist with "+plateNum);
return null;
}
Which consists of addVehicle methods, findVehicle etc.
Vehicle class:
public class Vehicle extends Owner{
PoliceStation ps = new PoliceStation("center");
String plateNumber;
String name;
String type;
//String serialNum;
public Vehicle(String driverName, String dateOfBirth,long ownerID, String address,String plateNumber, String name, String type) {
super(driverName,dateOfBirth,ownerID,address);
this.plateNumber = plateNumber;
this.name = name;
this.type = type;
}
With findVehicle method that should return the vehicle object with the vehicle's plate number:
public Vehicle findVehicle1(String plateNum) {
if(this.plateNumber==plateNum) {
System.out.println("Lookin "+plateNum);
return super.findVehicleObject(plateNum);
}else return null;
}
And after that I have a fourth class called RadioCam that reads a plateNumber from a car: (note: the following code is badly written because I've been trying to get this to work without success)
class RadioCam{
public void detection(double speed) {
System.out.println("Vehicle detected.");
//speed would be a variable that the radioCam would return using radiowaves and doppler effect
if(speed>50) {
String plateNumber = takePicture();
Vehicle veh = new Vehicle(plateNumber);
veh = veh.findVehicle1(plateNumber);//<-- null
System.out.println("-------------------"+veh.getName());//<- null here as well
Owner ownerFine = ps.getOwner(veh);
ownerFine= ps.getOwner(veh);
System.out.println("sssssss"+ownerFine.getName());
//ownerFine = PoliceStation.getOwner(veh);
ps.addFine(ownerFine, "speed violation", veh);//<- so this method doesnt work in the end becuse ownerFine and veh are null
Which returns null to veh = veh.findVehicle1(plateNumber);. And going back to Owner class at public Vehicle findVehicleObject(String plateNum) {
for(int i=0;i<vehicles.size();i++) { <-- vehicle.size() is 0 so it doesn't go through the vehicles at all.
I get it that I need an owner object from the arraylist to get to the vehicle object from the arraylist, but in this case I need a vehicle object from plateNumber (which is a part of the Vehicle class) and from the vehicle object to get the owner object that owns the vehicle object.
I hope I explained my problems good enough.
Try equals method to compare values, this.plateNumber==plateNum may be false even they have same value.
public Vehicle findVehicle1(String plateNum) {
if(this.plateNumber.equals(plateNum)) {
System.out.println("Lookin "+plateNum);
return super.findVehicleObject(plateNum);
}else return null;
}
In your findVehicle1(String plateNum) method you are comparing two strings with the == operator, while you should be using string.equals(Object other)
Try changing
if(this.plateNumber==plateNum) {
to
if(this.plateNumber.equals(plateNum)) {
Also when constructing your vehicle object, you're ommiting a lot of the needed parameters
public Vehicle(String driverName, String dateOfBirth,long ownerID, String address,String plateNumber, String name, String type) {
^ the constructor asks for 7 parameters, while you only give
new Vehicle(plateNumber);
one parameter. Therefore of course your veh.getName() method will return null, because it's an attribute that you did not maintain when you created your vehicle object.
After fixing those issues, you can think about your general code structure, like where to implement loops and such.
I don't know whether or not you use an IDE, but if you do please familiarize yourself with the the debugging functionality to follow the code execution step-by-step in called methods. You could have easily pinpointed the lines of code that act in ways they shouldn't act (after all you already found the lines where null is the result of your method calls).

ArrayList is being overwritten

I am trying to add a new train to my arraylist but upon adding the train, the existing content of the arraylist gets overwritten by the new input. This results in having only one item in the arraylist without being able to add more without overwriting the other. As I do not quite know what the source of this problem in the code is, I came looking for help here.
Within this class the train is being made:
public class RCommand extends RBaseListener {
Company mycompany = new Company("traincompany");
#Override
public void enterNewtraincommand(RParser.NewtraincommandContext ctx) {
System.out.println("Now creating new train " + ctx.getText());
mycompany.addTrainTo(new Train(ctx.getChild(2).toString()));
System.out.println(mycompany.getTrains().size());
}
}
In this class the train is supposed to be added to the list.
public class Company{
private String name;
List<Train>trains = new ArrayList<Train>();
public void addTrainTo(Train train) {
trains.add(train);
for (Train t :trains) {
System.out.println(t.getName());
}
}
}
Simply test for your class Company to see if if work
public class Test {
Company company = new Company();
public static void main(String[] args) {
Test test = new Test();
test.start();
}
private void start() {
System.out.println("IT work");
company.addTrainTo(new Train("One"));
System.out.println("End first add");
company.addTrainTo(new Train("two"));
System.out.println("End second add\n");
System.out.println("Follow example will not work");
company = new Company();
company.addTrainTo(new Train("One"));
System.out.println("End first add");
company = new Company(); // <--- create the ERROR
company.addTrainTo(new Train("two"));
System.out.println("End second add");
}
}
Suppose we have train as is:
public class Train {
private String name;
public Train(String name) {
this.name = "Train" + name;
}
public String getName() {
return name;
}
}
Output is:
IT work
Train One
End first add
Train One
Train two
End second add (it work fine)
Follow example will not work
Train One
End first add
Train two
End second add<- we miss the first train because we recreate the company instance
So it work.
So the error is not in this class Company.
Check if the caller of Company recreate the class Company before adding new train
Check class train if it has something strange (static attribute for name or similar)
Looks like new "trains" object is being created for each addition. After adding, try to print the address of "trains" object to find out for sure. You can print the address by System.out.println("trains address is: " + trains)
You did't pass for us all your code required but I think, you should create a Company constructor with your train List.
Something like that:
public class Company{
private String name;
List<Train>trains;
public Company(String name, List<Train> trains){
this.name = name;
this.trains = trains;
}
...
}
Then in your RCommand class use your new Constructor
Company mycompany = new Company(new ArrayList<Train> ,"traincompany");
And it will be fine. Your mistake in code is creating new trains list every time by calling new operator.

Populating JComboBox with custom objects stored in an ArrayList

I'm trying to populate a JComboBox with object names. The objects are of Category type and are stored in an ArrayList (named categoryList) in the Category class.
Here is the content of the Category class:
public class Category {
private static String catName;
private static List<Category> categoryList;
public static void addToCatList(String str)
{
Category cat = new Category();
Category.setCatName(str);
categoryList.add(cat);
}
public static List<Category> getCatList()
{
return categoryList;
}
public static String getCatName()
{
return catName;
}
public static void setCatName(String catName)
{
Category.catName = catName;
}
#Override
public String toString()
{
return catName;
}
}
Here is the code that populates the JCombobox (method name: populateComboBox()):
List<Category> catList = new ArrayList<Category>();
catList = Category.getCatList();
Category list[] = new Category[catList.size()];
list = catList.toArray(list);
for(int i = 0; i <list.length; i++)
{
selectCatComboBox.addItem(list[i].getCatName());
}
addItemDialog.setVisible(true);
When I populate the ArrayList with 2 objects, named Obj1 and Obj2, I get the following problems:
When populateComboBox() is invoked, the combo box only displays the second object i.e. it only displays Obj2. The expected display was Obj1, Obj2.
Since it only displays Obj2. When populateComboBox() is invoked twice, the combo box displays two Obj2. When invoked three times it displays three Obj2. i.e. the number of times the method gets invoked, the number of times Obj2 gets displayed in the combo box.
Should the categoryList ArrayList be inside the Category class? or should it be inside the control class? I'm a bit confused with this one.
Your problem is that your design is broken. Category's catName name field is static and so only one object exists for the entire class. If you change it, you change it class wide. This is why Obj1 and Obj2 (bad names for variables by the way) share the same name and display the same name.
This class should be broken into two classes, one say called Category that has no static fields, no List fields, has private instance fields, constructor(s), public methods, and another, perhaps called Categories, that holds a non-static ArrayList<Category>, with the addCategory(...) and such methods. Fix this first before concerning yourself with GUI, else you'll be building your house on a very shaky foundation. Whenever you create a static field, always ask yourself why you're doing this, and strongly consider seeing if you can make it instance instead.
First off, I wouldn't have a POJO (Plain Old Java Object) that contains a List of itself. Also, the key word "static" means you can have only one of the variable across all instances of an object.
public class Category {
private String name = null; // I always like to initialize my variables
public Category() {
// empty constructor method, but I like to have a no argument constructor
}
public Category(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return catName;
}
}
List<Category> catList = new ArrayList<>();
catList.add(new Category("Category 1"));
catList.add(new Category("Category 2"));
for (Category category : catList) {
selectCatComboBox.addItem(category.getName());
}
addItemDialog.setVisible(true);

Using Arrays.binarySearch on an array of Objects and looking for a String within the object

OK so I have the following Object class:
public class IntoleranceFood implements Comparable<IntoleranceFood>{
private int scoreInt;
public String foodName;
public IntoleranceFood(String food, int score) {
super();
this.foodName = food;
this.scoreInt = score;
}
//getters and setters
public String getFood() {
return foodName;
}
public void setFood(String food) {
this.foodName = food;
}
public int getScore() {
return scoreInt;
}
public void setScore(int score) {
this.scoreInt = score;
}
#Override
public String toString() {
return "Intolerance Food [Name=" + foodName + ", Score=" + scoreInt + "]";
}
#Override
public int compareTo(IntoleranceFood arg0) {
return toString().compareTo(arg0.toString());
}
}
And then in my Activity I have created an array for these objects to go into, and filled up the array with "IntoleranceFood" Objects:
int numFoodItemTypes = db.intoleranceFoodItemTypesTotal();
IntoleranceFood[] foodArray = new IntoleranceFood[numFoodItemTypes];
Cursor cAllFoodTypes = db.intoleranceFoodTypesList();
int foodItem = 0;
do{
foodArray[foodItem] = new IntoleranceFood(cAllFoodTypes.getString(0), 0);
foodItem++;
}while(cAllFoodTypes.moveToNext());
I managed to sort the array by implementing Comparable and the compareTo method in my Object class:
Arrays.sort(foodArray);
But I want to then search the array using binary search, and look for the position in the array where a certain Object with a specific food name (String) resides. But I dont know how to get the following code working, and specifically in terms of:
-binarySearch(Object[] array, Object value)
I don't know what to put in "Object value" so this:
Arrays.binarySearch(foodArray, "Cereal");
Is clearly wrong! But I'm not sure how to search the Object array for an Object containing the String food name "Cereal".
Thanks.
Yes so after the very useful reply below, I realsied what I need to be doing is:
IntoleranceFood searchOb = new IntoleranceFood("Cereal",0);
int searchIndex = Arrays.binarySearch(foodArray, searchOb);
And that works!
In my opinion your mistake is
Arrays.binarySearch(foodArray, "Cereal");
because "Cereal" is not the Object you are looking for and your array doesnt contain this object. The second parameter should be an instance of the IntoleranceFood class and "Cereal" is just a property of that class.
For your problem i would use a HashMap or another Map who fits your problem best!
Maybe this article will help you : How to sort a HashMap in Java

Basic Object Oriented Programming

I am currently studying Java and have been asked to write a program that deals with
actors and films as classes.
The actor class has the following attributes:
Name, Address, age, myFilm (an array or arraylist to hold all the films a particular actor
has starred in.
The film class has these attributes:
Name, Code (String, String)
I have implemented these classes with getter and setter methods to handle the data:
My actor class so far:
public class actor {
private String name;
private String address;
private int age;
int[] myFilms = new int[3];
public actor (String name, String address, int age) {
}
public void setName (String name) {
this.name = name;
}
public void setAddress (String address) {
this.address = address;
}
public void setAge (int age) {
this.age = age;
}
public void setFilm () {
}
public String getName () {
return name;
}
public String getAddress () {
return address;
}
}
My film class:
public class film {
private String name;
private String code;
//Constructor
public film () {
}
public void setName (String name) {
this.name = name;
}
public String getName (){
return name;
}
public String getCode (String name) {
//Get code:
//Split Function
String[] words = name.split("\\s+");
String code = "";
for (int i=0; i < words.length; i++) {
code = code + words[i].charAt(0);
code = code.toUpperCase();
}
return code;
}
}
I'm hitting a brick wall with how to approach making the program dynamic to display each actors total films. This is for a college assingnment and I am also required to do a deep copy of the array at some point. I am almost completely new to OO so this is proving a tricky task for me.
Any words of advice or a point in the right direction would be hugely appreciated.
Two comments about your classes...
Why not declare the films of an actor like this:
private List<Film> myFilms = new ArrayList<Film>();
This way, you will be able to add and remove film object references dinamically from your actor objects. You can implement getter and setter for the list and manipulate it from outside, for example. Lists (or Collections in general) are much easier to manipulate than primitive arrays.
Consider declaring classes with first capital letter, it's a convention. For example: Actor, Film.
Consider extracting a "actor that play in film" to another class, to decouple film out of actor (actor can also do theathre spectacles, vioce dubbig etc, not specialy movies.)
class ActorRole {
private Actor actor;
private Movie movie;
private int dollarsSallary;
private int scenesPlayed;
// etc.
}
If you don't want to, I'm almost sure that better create dependency from Movie to Actor than from Actor to Movie, because Movies almost surely have actos:
class Movie {
private List<Actor> actors = new ArrayList<Actor>();
}
This makes harder to count actor statistics (you have to iterate over all Movies) but I think this is a better design.
To count single actor shows:
for ( Movie movie : listOfAllMovies ) {
if ( movie.getActors().contains( myActor ) ) { // read about equals() in Java !
timesPlayed++;
}
}
If you want to make a ranking for more actors, you can use Map<Actor,Integer> to map actors to they times played counters.
This can be a lengthy operation, so you can think about cashing the results (like in above map) - the solution can be map, ActorStatistics class, simple timesPlayed field in actor etc. etc.
Don't be afraid to objects
Don't do a hard workaround to mape films to id (like your id, which is propably connected to your film code String, wich add another type-incompatibility issue.
Try to use more object references instead of workarounds, and List instead of array.
Generally, read about Collections in Java, like ArrayList and HashMap and also overriding equals() and hashCode(), and in general OOP Single responsibility principle and Class cohesion
You can compose a auto-increment container inside class actor, like vector ArrayList and so on. Or you could implement a dynamic array by yourself.
If u have a database which has a table with username and film(ID) & etc, u can create a class as follow,
Class Film{
private String actorName;
private String filmCode;
private String filmName;
....getter & setter methods
...
}
then u can create a method to get data list of Film class.
Eg:
List<Film> filmList = new ArrayList<Film>();
String actorName = "Arnold";
filmList = dbCon.getFilmListByActor(actorName);
your getFilmListByActor method should be like this,
public List<Film> getFilmListByActor(String actorName){
List<Film> filmList = new ArrayList<Film>();
//Query for get film list by actor
//assigne filmList to result set
enter code here
return filmList;
}

Categories

Resources