I'm new to java and am having issues understanding how to populate an array with object manually. Reason I wan't to do this manually is because I have 40 objects I need to create where 20 object go to arrayOne and other 20 objects go to arrayTwo. Also each object has a unique parameter like "Texas" or "Canada" that needs to be set.
I would usually create an array like this:
long[] arrayOne;
arrayOne = new long[20];
and than populate it with, lets say numbers through a loop or manually. However now I am dealing with objects and am struggling to figure it out, I tried looking up answers here at StackOverflow, but was not able to understand what was going on there exactly.
If it helps, this is a constructor for my object
// Plane Constructor
public Plane (int i, String dest, String airl, String airc, double t) {
planeID = i;
destination = dest;
airline = airl;
aircraft = airc;
time = t;
}// END Plane Constructor
I would suggest using an ArrayList instead of an array, because a list can grow but an array is a fixed size. However, to answer your question:
Plane[] arrayOne = new Plane[20];
Plane[] arrayTwo = new Plane[20];
arrayOne[0] = new Plane(1001, "Timbuktu");
arrayOne[1] = new Plane(2930, "Siberia");
// etc.
arrayTwo[0] = new Plane(2019, "France");
arrayTwo[1] = new Plane(1222, "Italy");
// etc.
If you used an ArrayList it would be:
List<Plane> arrayOne = new ArrayList<Plane>();
planes.add(new Plane(1001, "Timbuktu"));
planes.add(new Plane(2930, "Siberia"));
// etc.
Or, if you're really fancy:
List<Plane> planes = new ArrayList<Plane>() {{
add(new Plane(1001, "Timbuktu"));
add(new Plane(2930, "Siberia"));
}};
In all cases you can iterate over the contents as follows:
for (Plane plane : arrayOne) {
System.out.println(plane.getDestination());
}
Plane[] array = new Plane[10];
array[0] = new Plane(/*specify your parameters here*/)
Check out the chapter 10 of Java Language Specification.
You have to declare an array of objects (in this case Plane) just like you declare array of long - Plane[] arrayOne = new Plane[20];. Then you can access the elements using indices in the same manner. If you really have to populate it manually, you should do something like:
arrayOne[0] = new Plane(1, "foo", "bar", "baz", 1.0);
arrayOne[1] = new Plane(2, "fooo", "baar", "baaz", 2.0);
There are only two things that differ from the usage of Object[] array from long[] - type of the array and fact that at some point you have to use constructors to create objects. You can use a previously created object though.
U first create the Plane array:
Plane[] planes = new Plane[20];
then each object:
planes[0] = new Plane(...);
...
You can use a common interface if the elements of your array are not necessarily instances of Plane.
For instance:
package test;
public class Main {
public static void main(String[] args) {
Flyer[] flyers = new Flyer[] { new Plane(), new Bird() };
for (Flyer f: flyers) {
// you can only access method "fly" here, because it's the only
// method defined in your interface, but nothing
// stops you from adding more methods, as long as you implement
// them in the (non-abstract) classes
f.fly();
}
}
}
class Plane implements Flyer {
// TODO id, destination, airline, etc. getters/setters
#Override
public void fly() {
System.out.println("Weeee I'm flying!");
}
}
class Bird implements Flyer {
// TODO whatever properties / getters / setters
#Override
public void fly() {
System.out.println("Chirp chirp");
}
}
interface Flyer {
void fly();
}
Output:
Weeee I'm flying!
Chirp chirp
Related
In my program, I want to create multiple threads in one of the methods where each thread has to run a specific method with a given input. Using Runnable, I have written this snippet.
class myClass {
public myClass() { }
public void doProcess() {
List< String >[] ls;
ls = new List[2]; // two lists in one array
ls[0].add("1"); ls[0].add("2"); ls[0].add("3");
ls[1].add("4"); ls[1].add("5"); ls[1].add("6");
// create two threads
Runnable[] t = new Runnable[2];
for (int i = 0; i < 2; i++) {
t[ i ] = new Runnable() {
public void run() {
pleasePrint( ls[i] );
}
};
new Thread( t[i] ).start();
}
}
void pleasePrint( List< String > ss )
{
for (int i = 0; i < ss.size(); i++) {
System.out.print(ss.get(i)); // print the elements of one list
}
}
}
public class Threadtest {
public static void main(String[] args) {
myClass mc = new myClass();
mc.doProcess();
}
}
Please note, my big code looks like this. I mean in one method, doProcess(), I create an array of lists and put items in it. Then I want to create threads and pass each list to a method. It is possible to define the array and lists as private class members. But, I want to do that in this way.
Everything seems to be normal, however, I get this error at calling pleasePrint():
error: local variables referenced from an inner class must be final or effectively final
pleasePrint( ls[i] );
How can I fix that?
The reason you are getting this error is straightforward and clearly mentioned - local variables referenced from an inner class must be final or effectively final. This is, in turn, because, the language specification says so.
Quoting Guy Steele here:
Actually, the prototype implementation did allow non-final variables
to be referenced from within inner classes. There was an outcry from
users, complaining that they did not want this! The reason was interesting: in order to support such variables, it was necessary to
heap-allocate them, and (at that time, at least) the average Java
programmer was still pretty skittish about heap allocation and garbage
collection and all that. They disapproved of the language performing
heap allocation "under the table" when there was no occurrence of the
"new" keyword in sight.
As far as your implementation goes, instead of using an array of list, I'd rather use a list of lists.
private final List<List<String>> mainList = new ArrayList<>();
You can create new lists and insert them into the main list in the constructor depending on the number of lists you want.
public ListOfLists(int noOfLists) {
this.noOfLists = noOfLists;
for (int i = 0; i < noOfLists; i++) {
mainList.add(new ArrayList<>());
}
}
You can then change your doProcess() method as follows:
public void doProcess() {
for (int i = 0; i < noOfLists; i++) {
final int index = i;
// Using Lambda Expression as it is much cleaner
new Thread(() -> {
System.out.println(Thread.currentThread().getName());
pleasePrint(mainList.get(index)); // Pass each list for printing
}).start();
}
}
Note: I used an instance variable named noOfLists to (as the name suggests) store the number of lists I need. Something as follows:
private final int noOfLists;
To populate the list, you could do:
mainList.get(0).add("1");
mainList.get(0).add("2");
mainList.get(0).add("3");
mainList.get(1).add("4");
mainList.get(1).add("5");
mainList.get(1).add("6");
// And so on...
And you'll get the output something as:
Thread-0
1
2
3
Thread-1
4
5
6
Hope this helps :)
First to that, you will get a NullPointerException here:
ls[0].add("1"); ls[0].add("2"); ls[0].add("3");
ls[1].add("4"); ls[1].add("5"); ls[1].add("6");
Before, yo must instantiate the lists:
ls[0] = new ArrayList<>();
ls[1] = new ArrayList<>();
About the compiler error, try to define the array as final. Change:
List< String >[] ls;
ls = new List[2]; // two lists in one array
By:
final List< String >[] ls = new List[2]; // two lists in one array
This is because you can't access to non-final (or effectively final) variables from a local class.
'ls' is effectively final but probably, since you have defined it in two lines, the compiler is not able to notice that.
Hellow
I created a class Packet as followed
public class Packet
{
private long arrivalTime = 0;
private boolean classType = true;
public Packet(long arrivalTime, boolean classType)
{
this.arrivalTime = arrivalTime;
this.classType = classType;
}
In a program I have two methods;
public ArrayList<Packet> simulateArrProces (long loopCount)
{
//DO STUFF
}
public void enqueue(Packet...packets)
{
//DO STUFF
}
The objective is to use the ArrayList returned by the simulateArrProces method as an input for the enqueue method. I thought I could simply give the ArrayList of the first method, but this doesn't seem to work. I tried the following
Arrival arr = new Arrival(arrivalProces);
Queue que = new QueueFCFS();
List l = arr.simulateArrProces(0);
que.enqueue(l.toArray());
It is clear that I should tranform the returned ArrayList of simulateArrProces to something, but I don't find what to. I think this is due to the fact that I chose to use ' Packet ... packet ' , but I did not exactly get what this expression meant.
In short; two questions
1. How to transform the ArrayList returned by simulateArrProces to something I can use in the enqueue method.
2. What is the exact meaning of Packet... packets
The toArray method of Collection (from which Lists and subsequently ArrayLists inherit) features an overload, taking an (empty) array of T (your parametrized type) as parameter: this is what you should employ in order not to return an Object[].
In turn, this can be passed into a method taking a varargs of that type as parameter.
Example
Given...
List<String> foo() {
// just as example
return new ArrayList<String>();
}
void bar(String... s) {
// nope
}
Here are the "good" vs "bad" idioms available to you:
List<String> foo = foo();
// bad, casting Object[] as String[]
bar((String[])foo.toArray());
// good, populating a String[] of your List's size with your List's elements
bar(foo.toArray(new String[foo.size()]));
Let's start with Packet...packets. It's var-args feature of Java. This means that you can pass there any number of packet objects. Implicitly it converts to array of Packet so you can pass an array as well
Example 1:
class Packet {
// your implementation goes here
}
class SomeClassWithVarArgs{
void foo(Packet ... packet);
}
// So you can do the following:
Packet p1 = new Packet();
Packet p2 = new Packet();
Packet p3 = new Packet();
SomeClassWithVarArgs s = new SomeClassWithVarArgs();
// all these are legal
s.foo(p1, p2,p3);
s.foo(p1, p2);
s.foo(p3, p3,p3,p3,p3);
// implicit conversion to array:
Packet [] arrayOfPackets = new Packet[] {p1, p2,p3};
s.foo(arrayOfPackets);
Now regarding the toArray, it's just a compilation related issue you'll have to learn.
Obviously you can't pass neither ArrayList not List to enqueue(Packet... packets). So you've tried to convert the list to array and it's a good attempt. However toArray returns Object [] and obviously it's not what you want.
So you should use the following approach:
Example 2:
List<Packet> li = ...
Packet [] arr = li.toArray(new Packet[li.size()]);
// now you can pass it to enqueue method
enqueue(arr);
I have written a method (part of a program) which takes in two int values(code below). One int value representing number of guys for whom java training is completed and another int value for guys for whom php training is completed. I expect the arraylist to grow with every function call. Example: First time I called the function with values (5,0). So the arrayList for java would be [5] and for php it would be [0] . Next time I call the function with values (2,3). The arrayList for java should now be [5][2] and sum should be 7. The the arraylist for php should be [0][3] ans sum should be 3. The problem with my code is that when I call the method for the second time, it wipes away the [5](value of first index from the first call) in the java arrayList and just takes the form of [2] and gives the sum 2(instead of the required 7). The arrayList is never growing. (same for the php arrayList) I am sure I am doing something conceptually wrong here . Please help Somehow, the way I have coded it, every function call seems to make a new arrayList and not growing the arrayList obtained from the previous call.
public class TrainingCamp {
public static int trainedJavaGuys ;
public static int trainedPHPGuys ;
public void trainedTroopsInCamp(int java,int php){
//System.out.println("********* Current Status of Training Camp ********* ");
ArrayList<Integer> trainingListJava = new ArrayList<>();
trainingListJava.add(java);
//System.out.println("---JavaARRAYLIST----"+trainingListJava);
trainedJavaGuys = sumList(trainingListJava);
ArrayList<Integer> trainingListPHP = new ArrayList<>();
trainingListPHP.add(php);
trainedPHPGuys = sumList(trainingListPHP);
//System.out.println("---phpARRAYLIST----"+trainingListPHP);
Calling it like this from another class:
TrainingCamp currentTrainingCamp = new TrainingCamp();
currentTrainingCamp.trainedTroopsInCamp(2, 0);
and next time the same two lines get executed with just the input params changed
The arraylists are reinitialized each time you call trainedTroopsInCamp() because they are declared within it.
You should make the arraylists member variables, so that they only get initialized once, in the class's constructor.
public class TrainingCamp {
public static int trainedJavaGuys ;
public static int trainedPHPGuys ;
// Declare once
ArrayList<Integer> trainingListJava;
ArrayList<Integer> trainingListPHP;
public TrainingCamp() {
// Initialize once
trainingListJava = new ArrayList<>();
trainingListPHP = new ArrayList<>();
}
public void trainedTroopsInCamp(int java,int php){
// Use everywhere
trainingListJava.add(java);
trainedJavaGuys = sumList(trainingListJava);
trainingListPHP.add(php);
trainedPHPGuys = sumList(trainingListPHP);
}
}
you're re-initializing the list references in the method call, so every time you call the method you're using a new (empty) list.
instead, try keeping the lists as member variables for your class, something like this:
class TrainingCamp {
private final List<Integer> javaTrained = new LinkedList<>();
private final List<Integer> phpTrained = new LinkedList<>();
public void trainedTroopsInCamp(int java,int php){
//System.out.println("********* Current Status of Training Camp ********* ");
javaTrained.add(java);
trainedJavaGuys = sumList(javaTrained);
phpTrained.add(php);
trainedPHPGuys = sumList(phpTrained);
}
...
}
Hey I am new java so forgive me if what I am about to ask is obvious, but I will try to explain as best as I can.
Its just a project that has been set for university so its not in a serious manner.
I have a class called MarsRoom which holds the attributes say for all the dimensions of the room like the totalheight and width of the walls in order to calculate the heat loss that the room will suffer in order to adjust the amount of solar energy that is needed to keep the room at the room temperature set.
The problem I am having is what is better practice or solution, to pass the attributes of the size of the room in a constructor(but this could get quite long in size, as the ones below are not only the ones that I may need) or create a whole different class specifically for that room like ROOM TYPE U? and set the attributes in there.
As it stands I can create a whole new room just by instantiating the room with the new values, but its going to get a little long, whereas I would rather not create a whole new class for a different room which may only differ from another room by a few meters on one of the walls!.
So what I am really trying to get at it, is is it ok to pass that many attributes to the constructor on instantiation?
//the instantiation in the runnable
MarsRoom room1 = new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
//the constructor in the MarsRoom class
public MarsRoom(String roomname, int windowsH, int windowsW, int wallsH, int wallsW, int windowC, int heaters, int lights){
name = roomname;
TotalWindowHeight = windowsH;
TotalWindowWidth = windowsW;
TotalWallHeight = wallsH;
TotalWallWidth = wallsW;
windowCeiling = windowC;
numheaters = heaters;
numlights = lights;
roomheaters = new Heaters[numheaters];
}
I'd say that you should be adding factory methods here.
Basically, keep your constructor, but add methods like
static Room createLaundryRoom(laundryRoomParameters) {
return new Room(...laundry room parameters plus defaults
common to all laundry rooms...);
}
One of the great benefits object oriented programming is the possibility of not repeating yourself in code. Hence objects, which define data (members) and functionality (methods), and no requirement to create instances of these "prototypes" with hard values until run-time. To create a new class for each room when it
may only differ from another room by a few meters on one of the walls
would be to deny OOP (and Java) by gross repetition. I'd stick with the constructors, and if similar kinds of rooms end up emerging, try one of the static factory methods suggested, or break up common functionality using inheritanceOracle.
Create a map with the keys being
Map<String, Integer> map = new HashMap();
map.put("TotalWindowHeight", new Integer(10));
map.put("TotalWindowWidth", new Integer(5));
...
map.put("NumberOfHeaters", new Integer(3));
MarsRoom room1 = new MarsRoom("RoomU", map);
Constructor will be like:
public MarsRoom(String roomname, HashMap<String, Integer> params) {
name = roomname;
TotalWindowHeight = map.get("TotalWindowHeight").intValue();
TotalWindowWidth = map.get("TotalWindowWidth").intValue;
...
roomheaters = new Heaters[map.get("NumberOfHeaters").intValue()];
}
this is not good OO however, but it seems like you are looking for something quick. If you want good OO you need to create an object for Window and in it you have hieght and width, another for ceiling, and you should not have number of something as a field, you should have an array to store the heater objects, and so and so forth, but this is quick and meets your requirement.
While technically legal, constructors with very long argument lists may be inconvenient to use. It also depends on whether you this the list may grow in the future or in subclasses.
If you have many parameters, but they have defaults and sometimes only a few need to be changed, you may find the Builder pattern useful. The idea is to replace constructor arguments with function calls, and allow them to be chained, for example:
public MarsRoom() {
//empty or just basic stuff set here
}
public MarsRoom setTotalWindowHeight(int TotalWindowHeight) {
this.TotalWindowHeight = TotalWindowHeight;
return this;
}
public MarsRoom setTotalWindowWidth(int TotalWindowWidth) {
this.TotalWindowWidth = TotalWindowWidth;
return this;
}
...
then, you can call:
MarsRoom room1 = new MarsRoom()
.setTotalWindowHeight(20)
.setTotalWindowWidth(40);
Of course, if you wanted to set all parameters this way, it's longer (thou maybe more readable) than the single constructor. But if you only set 2 parameters out of 10, it will usually be more convenient.
You don't show what the fields of MarsRoom are, but for each feature, I would have a Collection of sub-objects. A MarsRoom has-a List of Windows. A MarsRoom has-a List of Walls. etc... Then have setters and getters for each and methods to add new instances of these features.
Since this is for school, I'm only including a little bit of pseudo code.
public class MarsWindow {
int height;
int length;
// Setters & Getters
// standard getters & setters go here
int getArea() {
return this.height * this.width;
}
}
public class MarsRoom {
List<MarsWindow> windows;
List<MarsWall> walls;
List<MarsLight> lights;
List<MarsHeater> heaters;
public List<MarsWindow> addWindow(MarsWindow window) {
// Add a window to the "windows" list here
}
public List<MarsWall> addWall(MarsWall wall) {
// Add a wall to the "walls" list here
}
// Do this for the other fields
int getTotalWindowArea() {
int area = 0;
// Iterate over all windows
for(MarsWindow window : windows) {
area += window.getArea();
}
return area;
}
// Add other calculation methods here
}
If what you're trying to do is simply not duplicate the parameters you're passing the constructor, you can simply put them in a separate static method, like so:
public static MarsRoom newRoomU() {
return new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
}
You could also use some polymorphism or have different types of rooms or something similar to this and then have a superclass with the common values that all rooms will have.
You can also have more than one constructor and have different ones for values you wish to set depending on the room type etc.
Its always better to work with objects rather than primitives, you could use factory to create objects.
//the constructor in the MarsRoom class
public MarsRoom(String roomname, WindowDimension windowDimension, WallsDimensions wallDimension, RoomAmbience ambience){
}
public class WindowDimension{
private int height; //int windowsH
private int width; //int windowsW
private int circumference; //assumed windowC is circumference
}
public class WallsDimension{
private int height; //int wallsH
private int width; //int wallsW
}
public class RoomAmbience{
private int heaters;
private int lights;
}
I started down this path of implementing a simple search in an array for a hw assignment without knowing we could use ArrayList. I realized it had some bugs in it and figured I'd still try to know what my bug is before using ArrayList. I basically have a class where I can add, remove, or search from an array.
public class AcmeLoanManager
{
public void addLoan(Loan h)
{
int loanId = h.getLoanId();
loanArray[loanId - 1] = h;
}
public Loan[] getAllLoans()
{
return loanArray;
}
public Loan[] findLoans(Person p)
{
//Loan[] searchedLoanArray = new Loan[10]; // create new array to hold searched values
searchedLoanArray = this.getAllLoans(); // fill new array with all values
// Looks through only valid array values, and if Person p does not match using Person.equals()
// sets that value to null.
for (int i = 0; i < searchedLoanArray.length; i++) {
if (searchedLoanArray[i] != null) {
if (!(searchedLoanArray[i].getClient().equals(p))) {
searchedLoanArray[i] = null;
}
}
}
return searchedLoanArray;
}
public void removeLoan(int loanId)
{
loanArray[loanId - 1] = null;
}
private Loan[] loanArray = new Loan[10];
private Loan[] searchedLoanArray = new Loan[10]; // separate array to hold values returned from search
}
When testing this, I thought it worked, but I think I am overwriting my member variable after I do a search. I initially thought that I could create a new Loan[] in the method and return that, but that didn't seem to work. Then I thought I could have two arrays. One that would not change, and the other just for the searched values. But I think I am not understanding something, like shallow vs deep copying???....
The return value from getAllLoans is overwriting the searchedLoanArray reference, which means that both loanArray and searchedLoanArray are pointing at the same underlying array. Try making searchedLoanArray a local variable, and then use Arrays.copyOf. If you're trying not to use standard functions for your homework, manually create a new Loan array of the same size as loanArray, and then loop and copy the values over.
your searchloanarray and loanarray point to the same array. doing this
private Loan[] searchedLoanArray = new Loan[10]
does nothing as you never use that new Loan[10]
this is the key to your problem
searchedLoanArray = this.getAllLoans()
that just points searchedLoanArray at loanArray
You could rewrite it like this:
public Loan[] findLoans(Person p)
{
Loan[] allLoans = this.getAllLoans();
System.arraycopy(allLoans, searchedLoanArray, 0, 0, allLoans.length); // fill new array with all values
// remainder of method the same
}
But as it stands, the code still has some problems:
The maximum number of loans is fixed to the size of the array. You will avoid this problem when you switch to List<Loan>.
Using the id as an index means that your ids must be carefully generated. If IDs come from a database, you may find that the list tries to allocate a huge amount of memory to size itself to match the Id. You would be better using a Map, then the size of the map is based on the number of loans, rather than their IDs.
As the number of people and loans increase, the search time will also increase. You can reduce search time to a constant (irrespective of how many People) by using a Map>, which allows quick lookup of the loans associated just with that person.
Here's a version with these changes:
class AcmeLoanManager
{
public void addLoan(Loan l)
{
Person client = l.getClient();
List<Loan> loans = clientLoans.get(l);
if (loans==null)
{
loans = new ArrayList();
clientLoans.put(client, loans);
}
loans.add(l);
allLoans.put(l.getLoanId(), l);
}
public void removeLoan(int loanId)
{
Loan l = loans.remove(loanId);
clientLoans.remove(loan);
}
public Collection<Loan> getAllLoans()
{
return loans.values();
}
public List<Loan> findLoans(Person p)
{
List<Loan> loans = clientLoans.get(p);
if (loans==null)
loans = Collections.emptyList();
return loans;
}
private Map<Integer,Loan> allLoans = new HashMap<Integer,Loan>();
private Map<Person, List<Loan>> clientLoans = new HashMap<Person,List<Loan>>();
}
I hope this helps!
What I would do is loop through the values and reassign each value to the new variable. Alternatively, you could use "deep copy" technique as described here in Javaworld: http://www.javaworld.com/javaworld/javatips/jw-javatip76.html