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);
Related
I have this code to create a class User
public class User {
private String name;
private ArrayList<User> owners = new ArrayList<>();
public User(String name, ArrayList<User> owners) {
this.name = name;
this.owners = owners;
}
public String getName() {
return name;
}
public void addOwner(User owner) {
owners.add(owner);
}
If i create an instance of this class with
User jhil = new User(name, new ArrayList<>());
What do i do to add a string element to the arraylist
I've tried with the addOwner method with
jhil.addOwner(jhilsara);
but i get a the method addOwner(String) is undefined for the type User error
I've also tried with the ArrayList add method
jhil.add(jhilsara);
But that doesn't work either.
So my question is what do i need to do in order to add something to the arraylist of an instanced of my class User
You have your ArrayList set to contain objects of the User class, not Strings. Change the declaration of it to:
private ArrayList<String> owners = new ArrayList<>();
Then, you also have to change addOwner to:
public void addOwner(String owner) {
owners.add(owner);
}
What is the best way to store a Collection<MyItem> ? This collection is effectively static for current user. Each user can only see their collection. MyItem item implements IItem:
public interface IItem {
public Integer getItemID();
public void setItemID(Integer id);
public String getTitle();
public void setTitle(String title);
/*more getters and setters*/
public IItem parseServerResponse(String response);
public int postItem(); //posts this IItem to server, return ok ->200, unauth->401, etc
public IItem findItem(String[] filters);
/*more advanced methods*/
}
I can store Collection<MyItem> elsewhere, but then I can't access private MyItem methods from CurrentMyItems:
public class CurrentMyItems{
private final List<IItem> allItemsList;
public CurrentMyItems(String allItemsServerResponseString){
JSONArray rawItems = parseResponse(allItemsServerResponseString);
int arrSize = rawItems.length()+estimateQuantityOfNewItems();
List<IItem> allItemsList = new ArrayList<>(arrSize);
for (int i = 0; i < Items.length(); i++) {
allItems.add(i, parseItem(Items.get(i)));
}
}
/*methods*/
}
Or inside of the MyItem class (see commented out options):
public class MyItem implements IItem {
/*
private final static List<IItem> allItemsStaticList = new ArrayList<>();
private final static Map<Integer, IItem> allItemsStaticMap = new HashMap<>();
private final List<IItem> allItemsList; //
private final static Map<Integer, IItem> allItemsMap;
*/
/*implemented methods*/
}
allItemsStaticList - stores a static list of all Items. Seems memory efficient, but what if I need to store separate collections of MyItems in future? This is highly unlikely, but still...
allItemsList - Same class has two distinct functions. It is either
storing a single Item, in which case allItemsList/Map = null;
or
allItemsList = new ArrayList<>();, while other fields are empty.
This seems OK, but it breaks the Least Surprise Principle.
Which approach to store a MyItemCollection is more natural?
Also, should I store Items as a Map or a List given that MyItem myItem = getMyItemByID(int id); is the main way to access MyItem?
Update
We can implement an Item class so that an instance can either hold a collection of Item instances or the modeled data, but not both.
public class Item {
private final Map<Integer, Item> itemsMap;
private final IntegerProperty itemID; // private final String[] names;
public Item(){
itemsMap = new HashMap<>();
itemID = null; //names = null;
}
private Item(Integer id) {
itemsMap= null;
itemID = new SimpleIntegerProperty(id); //names = new String[1];
}
public Item makeGenericItem(){
return itemsMap == null ? null : new Item(itemsMap.size());
}
// other methods, including getters and setters
}
But at what cost?.. This class violates single responsibility principle.
Conclusion - in most cases a Collection of Item instances should be stored outside of Item class.
In OOP the data elements of an object are also known as attributes of the object. So, you should ask yourself whether a collection of items is an attribute of an item or not.
For example, when you assume your items are students. Would you say that a list of students is an attribute of a student? -- Probably not, as a list of students is not part of a student. Instead a student is part of a list of students.
Since a list of students is not an attribute of students in real life, I would not model it differently in code just to make it technically more elegant.
The design of your classes should be driven by the structure of the domain that your are working in. When you need to decide where to put an attribute do not ask "does it make sense to put it here because of the features my programming language offers?" but ask "where does this attribute belongs to in my domain?".
In this project the user must enter 1 or 2 hospitals but not 3 or more. So the program starts and I display a menu. If the user presses 1 he must enter a hospital(name and department). After this the program displays the menu again and the user can choose to insert another hospital.
But after that, if I choose to insert another one (which is not permitted) the program accepts it. It seems that every time InsertHospitals() is called from the main class, the value of numberofhospitals (which is a counter counting how many hospitals I entered) equals 0.
public class Hospital {
private String Name, Departments;
private char flag;
private int numberofhospitals;
private Hospital[] ListOfHospitals;
//private Patient[] ListOfPatiens;
//private Doctor[] ListOfDoctors;
//private Examination[] ListOfExaminations;
//private Folder[] ListOfFolders;
public Hospital(String Name, String Departments)
{
this.Name=Name;
this.Departments=Departments;
}
public Hospital()
{
ListOfHospitals = new Hospital[2];
//ListOfPatiens = new Patient[100];
//ListOfDoctors = new Doctor[100];
//ListOfExaminations = new Examination[100];
//ListOfFolders = new Folder[100];
}
public String getName()
{
return Name;
}
public void setname(String Name)
{
this.Name=Name;
}
public String getDepartments()
{
return Departments;
}
public void setdepartments(String Departments)
{
this.Departments=Departments;
}
public void InsertHospitals()
{
if(numberofhospitals==2)
{
System.out.println("You can give only two hospitals!");
}
else
{
String temp = sir.readString("Hospital's Name:");
Name=temp;
String temp1 = sir.readString("Hospital's departments:");
Departments=temp1;
Hospital hospital = new Hospital(Name, Departments);
ListOfHospitals[numberofhospitals]=hospital;
numberofhospitals=numberofhospitals+1;
}
}
}
Your misunderstanding something, the list of hospitals (as mentioned) should not be inside your hospital class. You have to consider your hospital class as a blueprint you are using in your application.
Which means that you need to have a list of hospitals, as a list inside your other application class (which runs the application) and the InsertHospitals method should not be in your hospital class either obviously.
As you add a new hospital in your program, you create a new hospital object and add it to the list of hospitals (fx an arraylist) your keeping as a field value.
Also posssibly make a new constructor with parameters in the hospital class so you can insert the values outside of the class.
Something like this fx.
public class MainApp {
private ArrayList<Hospital> hospitalList;
public static void main(String[] args) {
// Initialize or load it from a file or whatever here.
hospitalList = new ArrayList<Hospital>();
// your code here...
}
public void insertHospital(<insert parameters here to create a hospital>) {
Hospital newHospital = new Hospital(<insert params with new constructor>);
hospitalList.add(newHospital);
}
}
Whatever your problem, your program completely wrong. In insertHospital() your changing Name and Departments fields, and creating new Hospital with those values. When you print Hospital information all hospitals will have the same value.
I am attempting to create an inventory tracking system. I have a class (in Java) called "InventoryItem" with the properties of name and quantity.
This works fine for simple objects, but what if my inventory item contains other inventory items, for example, a server with RAM?
Should I be creating my own datatype, or is there a better way to do this (linked listed maybe)? should my class extend whatever that datatype is or should I not bother creating my own class?
My class so far:
public class InventoryItem {
private String name;
private int quantity;
private InventoryItem childInventoryItem;
// CONSTRUCTORS
public InventoryItem() {
}
public InventoryItem(int quantity, String name) {
this.quantity = quantity;
this.name = name;
}
//GETTERS
public String getName() {
return name;
}
public int getQuantity() {
return quantity;
}
//SETTERS
public void setName(String name) {
this.name = name;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
A tree is usually what is involved in any parent-child relationship. If you aren't doing anything complicated, you can simply maintain an internal list that is basically List<InventoryItem> which contains any child items.
So all you would add to your class is something like this:
public class InventoryItem {
...
private List<InventoryItem> composingItems = new ArrayList<>(); //if still using Java 6 this must be new ArrayList<InventoryItem>();
...
public void addComposingItem(InventoryItem composingItem) {
composingItems.add(composingItems);
}
public List<InventoryItem> getComposingItems() {
//Enforce immutability so no one can mess with the collection. However
//this doesn't guarantee immutability for the objects inside the list;
//you will have to enforce that yourself.
return Collections.umodifiableList(composingItems);
}
}
There are many ways you can do this. I think the easiest way would be to create an array list.
ArrayList<InventoryItem> childInventory = new ArrayList<InventoryItem>();
Then create a setter that adds inventory items to this array
public void addChildItem(InventoryItem child)
childInventory.add(child);
This way you would have a list of all of the child items within the item. You could also make a method to return a list of all of the child items in either an array or an ArrayList.
public ArrayList<InventoryItem> getChildItems()
return childInventory;
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];