So lets say I have a class BaseballCard that creates a baseball card.
Now I need to make another class which would be my collection class.
For example I would call it BaseballCardCollection
and then I want to create methods like
size (which returns the numbers of cards in the collection)
addCard(adds a baseball object to the collection object)
removeCard (removes a baseball card)
and so on
What would be the best way to do this. I tried doing this
public CardCollectionList() {
BaseballCard[] baseballCardList = new BaseballCard[101];
}
So each object is insinuated with an array of type BaseballCard of size 100.
And then for example the size method I tried something like this
public int size(){
int size = 0;
for(int i = 1; i<this.baseballCardList.length; i++)
if (baseballCardList!= null)
size+=1;
}
But it doesn't work because "baseballCardList cannot be resolved to a variable"
You could try using ArrayLists - http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html:
ArrayList<baseballCard> baseballCardList = new ArrayList<baseballCard>(0);
public boolean addCard(baseballCard card){
return baseballCardList.add(card);
}
public boolean removeCard(int card){
return baseballCardList.remove(card);
}
public baseballCard getCard(int card){
return baseballCardList.get(card);
}
public int sizeBaseballCardList(){
return baseballCardList.size();
}
public ArrayList<baseballCard> getBaseballCardList(){
return baseballCardList;
}
Move the variable BaseballCard[] baseballCardList outside the constructor, make it a field in your class. Do similar with size.
This is how the class should look like:
public class CardCollectionList {
//fields
private BaseballCard[] baseballCardList;
private int size;
//constructor
public CardCollectionList() {
baseballCardList = new BaseballCard[101];
}
//method
public int getSize() {
return this.size;
}
}
You could try creating your own class implementing the Collection interface and define your own methods + implement Collection methods:
public class myContainer implements Collection <BaseballCard> {
}
You need to move the variable declaration from the constructor to the class, so you can access it in other methods, too.
class CardCollectionList {
BaseballCard[] baseballCardList;
public CardCollectionList() {
baseballCardList = new BaseballCard[101];
}
public int size(){
int size = 0;
for(int i = 1; i<this.baseballCardList.length; i++) {
if (baseballCardList[i] != null) {
size+=1;
}
}
return size;
}
}
The code is as close to your fragment as possible. There are several ways to improve this (keep track of the size when adding, automatic array reallocation etc.). But it is a start if you want to try this yourself.
Normally, you'd probably just use ArrayList<BaseballCard>.
Now I need to make another class which would be my collection class.
... What would be the best way to do this.
I don't have enough reputation to comment on your question, so I am going to assume that you just want to store BaseballCard objects in a Java Collection. The Java SDK offers a lot of options. Since you are asking about the "best" way to go then I would use one of those unless you need to add additional functionality .
if you don't find what you need from the Java SDK or just want to create your own Collection then follow the advice given by #michał-szydłowski above
Related
I am trying to write a program that contains many classes and in one class called "Dorm",I have an arrayList of Blocks,and in the "Block" class,I have an arrayList of Rooms,and in the "Room" class,I have an arrayList of "Students".
I am trying to access the number of available rooms(the rooms that at least have one empty space) through another class called the "Manager class". I have been told that I can just create another arrayList in the manager class to be used as a pointer and search up the empty rooms of the whole dormitory.
My question is,how is this going to work?
ps:This is what I wrote:
public static void availableRooms() { //Shows the available rooms in the dormitory.
Dorms dormitory = new Dorms();
Room room1 = new Room();
for(int i=0;i<dormitory.getBlocks().size();i++)
for(int j=0;j<Block.getRoomList().size();j++) {
if(!(room1.getStudentList().get(room1.getRoomCapacity()).equals(null)))
System.out.print("/t" + room1.getStudentList().get(i) + "/t");
}
}
My code isn't complete yet,so I'm not sure if it works...
Could you share your code/tentative? and clearly specify what's not working?
This being said, unless tied to specific constraints, one should make use of encapsulation and single responsibility principle (see SOLID on wiki) by keeping implementation details private and delegating tasks to the more relevant classes.
You may have something like:
class Dorm {
private List<Block> blocks = ...
...
public int getAvailableRooms() {
int total = 0;
for (Block b : blocks) {
total += b.getAvailableRooms();
}
return total;
}
}
class Block {
private List<Room> rooms = ....
...
public int getAvailableRooms() {
int total = 0;
for (Room r : rooms) {
if (! r.isFull()) {
total++;
}
}
}
class Room {
private int capacity = ...
private List<Student> students = ..
...
public boolean isFull() {
return capacity == students.size();
}
}
Where the Manager class, holding (an) instance(s) of Dorm, just make use of the getAvailableRooms() method which behind the scene delegate to the underlining Blocks and aggregate result... and so on.
In the interest of not creating more variables than necessary and cluttering up within the scope of a method that could otherwise have been very slim, I've, instead, created a temporary to hold all of the files I'm going to be referencing throughout the rest of the method.
I dislike this solution because it creates an array object every time it is run when an array object is not necessary to be created.
I could also not use the array or wall of variables, and instead reference the get methods directly, but that creates a lot of redundancy as I am performing the same methods repeatedly, and I dislike that even more.
public void savePrices() {
MFilePrices file[] = {AutoEcon.files().getPrices(), AutoEcon.files().getIntangibles(), AutoEcon.files().getGroups()};
for (String price : sellPrices.keySet()) {
if (EconItem.fromString(price) != null) {
file[0].setPrice(price, sellPrices.get(price).getExpression());
file[0].setBuyRate(price, sellPrices.get(price).getBuyRate());
} else if (file[1].getLabels().contains(price)) {
file[1].setPrice(price, sellPrices.get(price).getExpression());
file[1].setBuyRate(price, sellPrices.get(price).getBuyRate());
} else if (file[2].getLabels().contains(price)) {
file[2].setPrice(price, sellPrices.get(price).getExpression());
file[2].setBuyRate(price, sellPrices.get(price).getBuyRate());
}
}
}
public Double setExpression(String id, String expr) {
savePrices();
MFilePrices file[] = {AutoEcon.files().getPrices(), AutoEcon.files().getIntangibles(), AutoEcon.files().getGroups()};
if (EconItem.fromString(id) != null)
file[0].setPrice(id, expr);
else if (file[1].getLabels().contains(id))
file[1].setPrice(id, expr);
else if (file[2].getLabels().contains(id))
file[2].setPrice(id, expr);
else return null;
sellPrices.clear();
total=0;
loadPrices(AutoEcon.plugin());
return sellPrices.get(id).getPrice();
}
Another solution could be to create an array within the FilePool class where I'm getting the files from, which contains those three configuration files, or a method which puts them into an array and sends over the array. However, the latter just moves the problem over to another class, and the former is still creating a single array that is not totally necessary.
Both of these solutions just moves the problem from one class to another.
public class FilePool {
private Config config;
private Prices prices;
private Intangibles i;
private Groups groups;
private Logs econLogs;
private ItemAliases a;
public FilePool(AutoEcon pl) {
config = new Config(pl);
prices = new Prices(pl);
i = new Intangibles(pl);
econLogs = new Logs(pl);
a = new ItemAliases(pl);
new ReadMe(pl);
}
public Config getConfig() {
return config;
}
public Prices getPrices() {
return prices;
}
public Groups getGroups() {
return groups;
}
public Intangibles getIntangibles() {
return i;
}
public Logs getLogs() {
return econLogs;
}
public ItemAliases getAliases() {
return a;
}
}
(Ignore the dumb variable names in the FilePool class, I just loved the fact that they all line up so perfectly. Will be naming appropriately before publishing)
I know I'm being a bit over-anal about this tiny thing that won't affect the running program at all, but after being constantly harassed for every minor detail of my code by my colleagues in the past, I've grown to be a bit of a perfectionist.
Thanks to anyone who spent their time reading this. <3
The creation of the array is not a problem. Resources to create an array are meaningless. What is more of a problem is that anyone reading your code will struggle to understand what the magic indices represent without referring back to the array. Which means that you should turn them into named constants which will complicate your code even further.
Much better is to have clear variable names that represent what each element represents. Also a good idea to iterate through the map so you can avoid getting the value for each item:
FilePool files = AutoEcon.files();
final MFilePrices prices = files.getPrices();
final MFilePrices intangibles = files.getIntangibles();
final MFilePrices groups = files.getGroups();
sellPrices.forEach((price, value) -> {
if (EconItem.fromString(price) != null) {
setPriceAndBuyRate(prices, price, value);
} else if (intangibles.getLabels().contains(price)) {
setPriceAndBuyRate(intangibles, price, value);
} else if (groups.getLabels().contains(price)) {
setPriceAndBuyRate(groups, price, value);
}
});
private void setPriceAndBuyRate(MFilePrices filePrices, Price price, Value value) {
filePrices.setPrice(price, value.getExpression());
filePrices.setBuyRate(price, value.getBuyRate());
}
If you're concerned that the number of variables make the method difficult to read then move the logic for comparing the price to the labels and setting the price and buy rate into a separate class. That's a good practice in any case as it gives the class a single reason to change.
I'm sitting on an assignment for university and I'm at a point, where I fear I haven't really understood something fundamental in the concecpt of Java or OOP altogether. I'll try to make it as short as possible (maybe it's sufficient to just look at the 3rd code segment, but I just wanted to make sure, I included enough detail). I am to write a little employee management. One class within this project is the employeeManagement itself and this class should possess a method for sorting employees by first letter via bubblesort.
I have written 3 classes for this: The first one is "Employee", which contains a name and an ID (a running number) , getter and setter methods and one method for checking whether the first letter of one employee is smaller (lower in the alphabet) than the other. It looks like this:
static boolean isSmaller(Employee source, Employee target) {
char[] sourceArray = new char[source.name.length()];
char[] targetArray = new char[target.name.length()];
sourceArray = source.name.toCharArray();
targetArray = target.name.toCharArray();
if(sourceArray[0] < targetArray[0])
return true;
else
return false;
}
I tested it and it seems to work for my case. Now there's another class called EmployeeList and it manages the employees via an array of employees ("Employee" objects). The size of this array is determined via constructor. My code looks like this:
public class EmployeeList {
/*attributes*/
private int size;
private Employee[] employeeArray;
/* constructor */
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
}
/* methods */
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/* adds employee to end of the list. Returns false, if list is too small */
boolean add(Employee m) {
int id = m.getID();
if (id > employeeArray.length) {
return false;
} else {
employeeArray[id] = m;
return true;
}
}
/* returns employee at certain position */
Employee get(int index) {
return employeeArray[index];
}
/* Sets employee at certain position. Returns null, if position doesn't exist. Else returns old value. */
Employee set(int index, Employee m) {
if (employeeArray[index] == null) {
return null;
} else {
Employee before = employeeArray[index];
employeeArray[index] = m;
return before;
}
}
Now comes my real problem: In a third class called "employeeManagement" I am supposed to implement the sorting algorithm. The class looks like this:
public class EmployeeManagement {
private EmployeeList ml = new EmployeeList(3);
public boolean addEmployee(Employee e) {
return ml.add(e);
}
public void sortEmployee() {
System.out.println(ml.getSize()); // I wrote this for debugging, exactly here lies my problem
for (int n = ml.getSize(); n > 1; n--) {
for (int i = 0; i < n - 1; i++) {
if (Employee.isSmaller(ml.get(i), ml.get(i + 1)) == false) {
Employee old = ml.set(i, ml.get(i + 1));
ml.set(i+1, old);
}
}
}
}
The "println" before my comment returns "0" in console... I am expecting "3" as this is the size I gave the "EmployeeList" as parameter of the constructor within my "EmployeeManagement" class. Where is my mistake ? And how can I access the size of the object I created in the "EmployeeManagement" class (the "3") ? I'm really looking forward to your answers!
Thanks,
Phreneticus
You are not storing size in your constructor. Something like,
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
this.size = size; // <-- add this.
}
Also, setSize isn't going to automatically copy (and grow) the array. You will need to copy the array, because Java arrays have a fixed length. Finally, you don't really need size here since employeeArray has a length.
The size variable you are calling is the class field. If you take a quick look at your code, the getter is getting the field (which is initialized as zero when created). The size you are using it. The good way of doing it would be to get the size of the array in the getter like this:
public int getSize() {
return employeeArray.length;
}
This would return the size of the array in the object.
I'm using a arraylist to add states(the board state for the 8 puzzle). My problem is when I get the children of the state it changes the values stored in my array list. I'm assuming this is because ArrayList just stores pointers to the objects and not the values themselves. In order to fix this I create a new object every time before I store it into the ArrayList but I'm still having the same problem.
I will also try to follow naming conventions more often thanks for the tip.
private ArrayList<int[][]>VisitedBoard;
if(RuleNumber ==2){
//Here is my problem. This will change what is stored in VistedBoards
NextState = new State(FireRule.Rule2(WM.get_Board()));//Fire Rule
for(int j=0;j<VisitedBoards.size();j++){
//Meaning this will always be true
if(Arrays.equals(VisitedBoards.get(j), NextState.get_Board())){
Loop =true; //Loop to previous state
}
if(j==VisitedBoards.size()-1 && Loop ==false){ //If the next state is not any previously visited
NotALoop =true;
VisitedBoards.add(NextState.get_Board());
WM.set_Board(NextState.get_Board());
}
}
}
public int[][] Rule2(int [][] Board){//The FireRule Class
Find_BlankLocation(Board);
int temp;
State NewState;
temp = Board[BlankLocation[0]-1][BlankLocation[1]];
Board[BlankLocation[0]-1][BlankLocation[1]] = 0;
Board[BlankLocation[0]][BlankLocation[1]] = temp;
NewState = new State(Board);
return Board;
}
public class State { //State class
private int[][] Board;
private int[][] Goal;
private Boolean GoalFound;
public State(int[][] Start, int[][] goal){
Board = Start;
Goal = goal;
GoalFound=false;
}
public State(int[][] NewState){
Board=NewState;
}
public int[][] get_Goal(){
return Goal;
}
public int[][] get_Board(){
return Board;
}
public void set_Board(int[][] board){
Board = board;
}
public Boolean get_GoalFound(){
return GoalFound;
}
}
Containers like ArrayList work the same in all languages: they are called data structures because they organize storage/retrieval of objects. Obviously they don't store the fields of the objects themselves.
Trying to interpret your problem, maybe you don't want to share the boards between the list of visitedBoards and WM (whatever it means...). Then simply implement get_Board() to return a copy of the array instead of the Board object itself:
public int[][] get_Board(int[][] src) {
int[][] dst = new int[src.length][src[0].length];
for (int i = 0; i < src.length; i++) {
System.arraycopy(src[i], 0, dst[i], 0, src[i].length);
}
return dst;return dst;
}
Beside this, as others already told you, you'd really better to adopt the standard Java naming conventions, use meaningful names, and encapsulate your x, y and int[][] in real application classes.
Presumably, the new State object contains a pointer to the same arrayList as before. You'll want to manually copy the array out to a new one (a "deep clone" or "deep copy" as it is called). You might find this useful: Deep cloning multidimensional arrays in Java...?
Every time you create a new instance of State, you pass it the same array (whatever is returned by WM.get_Board()).
You then add that same array to VisitedBoards when you call VisitedBoards.add().
The fact that you're creating new State objects is irrelevant, because only the return value of NextState.get_Board() gets added to the list.
As a result, the list VisitedBoards always contains several references to the exact same array.
As Raffaele has suggested, you'll be fine if you make sure get_Board() returns a copy of the array in stead of a reference to the original (assuming that doesn't mess up logic that exists elsewhere).
The main thing I learned from this question is how important it is to follow naming conventions.
Your unconventional capitalization has made me dizzy!
Following these rules will make it much easier for others to understand your Java code:
class names should be capitalized (ie PascalCase)
variable names should be lowercase (ie camelCase)
do not use underscores in method names, class names, or variable names (they should only be used for constants)
always use meaningful names when possible
My advice is to create your own container object for their 2D array and implement deep copying.
For example:
package netbeans;
import java.util.Arrays;
public class Container
implements Cloneable
{
private int [] _data;
private int _sx;
private int _sy;
public int get(int x, int y)
{
try { return this._data[y*this._sx+x]; }
catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}
public void set(int x, int y, int value)
{
try { this._data[y*this._sx+x] = value; }
catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}
public Object Clone() { return new Container(this); }
public Container(int sizeX, int sizeY, int [] data)
{
this._sx = sizeX;
this._sy = sizeY;
this._data = data;
}
public Container(Container cont)
{
this._data = Arrays.copyOf(cont._data, cont._data.length);
}
}
I recently came across a very stupid (at least from my point of view) implementation inside Androids Parcel class.
Suppose I have a simple class like this
class Foo implements Parcelable{
private String[] bars;
//other members
public in describeContents(){
return 0;
}
public void writeToParcel(Parcel dest, int flags){
dest.writeStringArray(bars);
//parcel others
}
private Foo(Parcel source){
source.readStringArray(bars);
//unparcel other members
}
public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>(){
public Foo createFromParcel(Parcel source){
return new Foo(source);
}
public Foo[] newArray(int size){
return new Foo[size];
}
};
}
Now, if I want to Parcel a Foo Object and bars is null I see no way to recover from this situation (exept of catching Exceptions of course). Here is the implementation of these two methods from Parcel:
public final void writeStringArray(String[] val) {
if (val != null) {
int N = val.length;
writeInt(N);
for (int i=0; i<N; i++) {
writeString(val[i]);
}
} else {
writeInt(-1);
}
}
public final void readStringArray(String[] val) {
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
val[i] = readString();
}
} else {
throw new RuntimeException("bad array lengths");
}
}
So writeStringArray is fine if I pass bars which are null. It just writes -1 to the Parcel. But How is the method readStringArray supposed to get used? If I pass bars inside (which of course is null) I will get a NullPointerException from val.length. If I create bars before like say bars = new String[???] I don't get any clue how big it should be. If the size doesn't match what was written inside I recieve a RuntimeException.
Why is readStringArray not aware of a result of -1 which gets written on null objects from writeStringArray and just returns?
The only way I see is to save the size of bars before I call writeStringArray(String[]) which makes this method kind of useless. It will also redundatly save the size of the Array twice (one time for me to remember, the second time from writeStringArray).
Does anyone know how these two methods are supposed to be used, as there is NO java-doc for them on top?
You should use Parcel.createStringArray() in your case.
I can't imagine a proper use-case for Parcel.readStringArray(String[] val) but in order to use it you have to know the exact size of array and manually allocate it.
It's not really clear from the (lack of) documentation but readStringArray() is to be used when the object already knows how to create the string array before calling this function; for example when it's statistically instanciated or it's size is known from another previously read value.
What you need here is to call the function createStringArray() instead.