I am confused about how the array was assigned to any data, as the method meant to be a self contain
or I haven't understood a fundamental concept
// Craft stall stock and till program
import java.util.Scanner;
public class revisonTest {
public static void main(String[] args) // where program exicutes
{
final int numOFitems = 50;
String[] item = new String[numOFitems];
int [] broughtItem = new int[numOFitems];
int[] costItem = new int[numOFitems];
int COUNT = getDetail(item,broughtItem,costItem);
System.out.println(item[0]);
}
public static int getDetail(String[] name,int[] quantities,int[]cost)
{
int count =1;
int arrayIndex =0;
String answer = "";
while(!(answer.equals("Exit")))
{
answer = userInput("Item"+count+": ");
if(!(answer.equals("Exit")))
{
name[arrayIndex] = answer;
quantities[arrayIndex] = Integer.parseInt(userInput("How many "+name[arrayIndex]+" have you brought? "));
cost[arrayIndex] = Integer.parseInt(userInput("How much does a "+name[arrayIndex]+" cost? "));
count++;
arrayIndex++;
}
}
return count;
}
public static String userInput(String question)
{
Scanner sc = new Scanner(System.in);
System.out.println(question);
return sc.nextLine();
}
}
String[] item = new String[numOFitems];
This first makes a new treasure map named 'item'.
This makes a new treasurechest capable of containing numOFitems treasuremaps, and buries it in the sand. It is then filled with that many blank maps that lead to no treasure.
This updates your item treasuremap to point at this treasurechest-containing-maps.
getDetail(item,broughtItem,costItem);
This takes your treasuremap to the treasure-of-maps and makes a copy of it, and then hands the copy to the getDetail method. Your copy is unmodified and cannot be modified by getDetail... but that's just your copy of the treasure MAP, not the treasure. Note that getDetail calls this copy name and not item - which it is free to do.
(in getDetail) name[arrayIndex] = answer;
This is getDetail taking its name treasuremap (which is a copy of main's item map), follows the map, gets a shovel out, digs down, finds the treasure, opens it, finds the arrayIndexth map in it, pulls it up, and copies its answer map onto it.
Thus.. when main follows its copy of its map to the same treasure, same thing happens.
Of course, in java we use different jargon.
'treasure' -> 'object'
'treasuremap' -> 'reference'
'follow the map, dig down, open treasure' -> 'dereference'.
'create treasure' -> 'instantiate an object'
There are two different concepts here:
Allocating an array and assigning an array reference to a variable, and
Assigning values to elements in the array
In main, the new operation creates an array of a certain size, and assigns a reference to that array to the variable named item.
The call of getDetail(item,...) makes a copy of that reference (not the array itself) available to the method. Inside getDetail, this reference is stored in what is effectively a local variable, named name.
The loop inside getDetail is collecting answers (which are actually String references) and storing them in successive elements of the array that it knows as name and which the caller knows as item.
name[arrayIndex] = answer;
(Similarly for the other two arrays, of course)
In summary, getDetail is provided with an existing array, into which it writes values.
Incidentally, if the user types too many answers (more than name.length) you'll run off the end of the array, and get an 'index out of bounds' exception.
A String in java is considered a non-primitive data type. So when you created your item array using:
String[] item = new String[numOFitems];
You actually created an empty array of String objects. Based on your code the array has 50 empty spaces where you can store data.
The next part of your code is designed to get input from the user and fill those arrays:
int COUNT = getDetail(item,broughtItem,costItem);
Note: getDetail() never returns the item[] array, so how do you access the data?
When you pass your item array as an argument to the getDetail() method, you are actually passing that array as a reference.
In Java, non-primitive data types are passed as reference. This means that instead of sending the data to the getDetail() method, your actually sending information about where the data is located in memory.
Within your getDetail() method you can manipulate the data and the changes will be reflected on the original array without having to return it.
That is the reason why your print statement shows data in the array:
System.out.println(item[0]);
Any changes made within the getDetail() method, to the array, automatically appear on the original data source.
Related
I've been teaching myself java out of a book and I am trying to find out if I have a void method and I pass in two empty arrays through its parameter list, how can I use the methods parameters for later use. So for instance I put in 3 names with there score in like this " John Doe 98.3 " don't mind the parentheses. I want to make a sorting method later and be able to call that to sort the arrays String[] score, String[] names in the parameter list. In main after I call the method I try to print the array that I used for the parameter (on line 26 for me) but it returns null. How do I get the parameter list data from this void method?
Would prefer not to use objects unless there is no other way. Thanks for the insight.
// imports
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Example {
public static Scanner input = new Scanner(System.in);
public static void main(String[] args) {
int n;
n = numOfStudents();
input.nextLine();
String[] studentScore;
studentScore = new String[n];
String[] studentNames;
studentNames = new String[n];
studentInfo(n, studentScore, studentNames);
// prints null
System.out.println(studentNames[1]);
}
public static int numOfStudents(){
int students = 0;
System.out.print("Enter the number of students: ");
students = input.nextInt();
while (students < 1) {
System.out.print("Number of students must be greater than 0: ");
students = input.nextInt();
}
return students;
}
public static void studentInfo(int num, String[] score, String[] names){
String[] arr;
arr = new String[num];
score = new String[num];
names = new String[num];
String strPattern = "-?\\d+(\\.\\d+)?";
for(int i = 0; i < num; i++) {
System.out.print("Enter a name and test score: ");
arr[i] =input.nextLine();
Pattern pattern = Pattern.compile(strPattern);
Matcher matcher = pattern.matcher(arr[i]);
while (matcher.find()) {
score[i] = matcher.group();
}
names[i] = arr[i].replaceAll(strPattern, "");
}
System.out.println(score[1] + names[1]);
}
}
The trick is to know the difference between a reference and an object.
In java, all variables can only hold a small, fixed size amount of data, no exceptions. So, how in the blazes does Person p = new Person(); work, you should be wondering - you can make your own Person class and stuff it to the gills with fields with no issue; clearly a Person object can easily be neither small nor fixed size.
References is the answer.
This is what happens:
An object is created by invoking the Person constructor.
The reference to this object is the value of this invocation.
Your p variable holds this reference. This is a pointer; it lets java know where to find the object. It is not the object itself.
Imagine a giant beach. Objects are buried treasure. Variables are treasure maps written on little wipeable handheld whiteboards.
Person p = new Person();
is thus equivalent to:
Create a new treasure chest.
Bury it.
Draw the location to it on a map.
Return the map.
Next important thing to keep in mind: Java is pass by value. In java, those little whiteboards are never passed. Whatever whiteboards you hold are yours and yours alone. You cannot give them away nor receive any. Instead, whenever you want to give data to a method, you can instead show them what to copy on their whiteboards, and similarly, when a method returns information to you, all you get to is copy what is on their whiteboard.
Final important realization: Primitives (long, int, short, byte, double, float, boolean, and char - the list is hardcoded, you can't make your own) are all small and fixed size and just fit on these little whiteboards.
This explanation isn't 'java is a lot like this'. Nono, java is exactly like this. This metaphor does not have any failure modes; it is a pirate, beaches, and whiteboards version of how java works.
Note that = is assignment: In our pirate world it is the equivalent of wiping out a little whiteboard and copying something else on it. In contrast to foo.bar, foo[x], synchronized (foo), switch (foo) - these all dereference, meaning: In our pirate world those all involve: "Follow the map and dig in the sand".
Putting it all together, it explains the behaviour you witness. Let's go line by line through your code:
String[] studentScore;
Conjure out of thin air a new whiteboard. We shall name it studentScore, and we restrict it: It may either be blank, or have a map that leads to treasure of the String[] type; it is completely impossible to make maps to any other kind of treasure with it, the universe (the JVM) won't let it happen.
studentScore = new String[n];
This does multiple separate things. First, it conjures up a new treasure chest. It contains just enough room for n treasure maps (it's more like a little file folder than a big chest). After all, Strings themselves are objects too - they are treasures, and all string variables and references are therefore maps, not the whole thing. An array that can hold 'n' strings really just holds n treasure maps to strings. Next, this says: Draw on your studentScore whiteboard a map to this newly conjured up treasure file folder. Like all arrays of non-primitive types, it starts out with n blank maps. (a blank map = a null value).
studentInfo(n, studentScore, studentNames);
Your whiteboards are yours and cannot be handed out. So, this means: Walk over to Misses studentInfo. studentInfo knows how many arguments it has (in java all methods always have a set number of arguments), so she's ready to do your bidding, holding 3 fresh new blank whiteboards. You show her 3 whiteboards of your own: One with n written on it directly (n is an int, a primitive, therefore it's just written on your board. There's no map and no treasure involved), one with a treasure map leading to your studentScore buried treasure, and one to another buried treasure chest. Misses studentInfo duly copies these values and maps over on her 3 boards and goes to work.
score = new String[num];
Misses studentInfo takes her treasure map to the treasure you made and buried and wipes it clean, then, she conjures up an entirely new treasure chest, buries it, and copies the location over on her whiteboard.
score[i] = matcher.group();
Misses studentInfo fetches a shovel, follows her score treasuremap, digs down, and opens the treasure, which is a file folder with room for a bunch of treasure maps written on little whiteboards. She finds the i-th whiteboard, takes it out, wipes out whatever is there, and copies the treasuremap over that Mr matcher is currently showing her, as a result of doing his thing.
... method ends ....
Misses studentInfo is done, and she returns nothing, so she takes her whiteboards and tosses them in the garbage.
You are standing there, your whiteboards are of course still completely unmodified, maps to treasure that nobody touched - maps to treasures that still hold all blank maps. You fetch a shovel, follow your map, dig down, open the file folder, and pull out the first little whiteboard. Of course it is blank.
So how do you 'fix' this?
Don't use = in your studentInfo method. Alternatively, do that, but return that value (you can only return one thing, so if your method needs to modify 2 treasure chests, that 'return it' plan is not going to work out).
Just ditch the score = new String[num]; part. If you do not do that, then your line of score[i] = foo digs down to find the treasure that the map misses studentInfo copied over from your little whiteboard leads to. And then she modifies what she finds there - which is great, because when you follow your map, it's a different map, but goes to the same place, so when you dig down, you'll see the effects of what Misses studentInfo did.
I'm a beginner in Java I have some questions regarding the enhanced for loop and string arrays.
In the source code below, I've been trying to change the contents of the arrays using the enhanced-for loops.
It seems that I can't change the contents in the the String array(arrString), but I don't know exactly why. (It works fine for StringBuilder objects.)
I am a bit confused because I could actually do operations like str1+=str2 and change the String contents (although this operation is done via StringBuilder class) in normal situations.
Can anyone point out why this is happening and if there's any misunderstanding on my part?
class EnhancedForTest{
public static void main(String[] args){
//StringBuilder
StringBuilder[] arrStringBuilder=new StringBuilder[]{new StringBuilder("Hello1"), new
StringBuilder("Hello2"),new StringBuilder("Hello3")};
for(StringBuilder e: arrStringBuilder){
e.append("!");
}
for(StringBuilder e:arrStringBuilder){
System.out.println(e);
}
//String
String[] arrString=new String[]{"Hello1","Hello2","Hello3"};
for(String s:arrString){
s+="!";
}
for(String s:arrString){
System.out.println(s);
}
}
}
The results are as follows(Sorry I didn't add the results!):
Hello1!
Hello2!
Hello3!
Hello1
Hello2
Hello3
P.S.: I've taken out the printing line as a new for loop, it still works for StringBuilder but not String
On each iteration of the for-each loop the variable obtains a reference to the corresponding element of the array. In the case of for(StringBuilder e:arrStringBuilder) on the first iteration a new variable e of type StringBuilder will point to the same object as arrStringBuilder[0]. Then you call append using this reference, which performs operations on the object pointed by both references e and arrStringBuilder[0]. On the next iteration e will be assigned reference to arrStringBuilder[1], but the changes made in arrStringBuilder[0] will stay.
In the case of for(String s:arrString) on the first iteration a new variable s will be created pointing to arrString[0]. However, when you do s += '!' you actually perform s = s + '!', so you assign to this temporary variable s a reference to the new String object, which will contain Hello1!. This new object, however, is not related in any way to the original arrString[0] object, and at the start of the next iteration is just discarded. Your loop works like this:
for(int i = 0; i < 3; i++) {
// Create a temporary variable which points to the same object as arrString[i]
String s = arrString[i];
// Create a temporary object which keeps the result of concatenation of s and '!'
String temporary = s + '!';
// Replace the reference stored in s with the reference to the temporary object
s = temporary;
// Now there is no connection between s and arrString[i]
// And here we just discard both temporary objects 's' and 'temporary'
// arrString[i] object remains unchanged.
}
e.append("!"); is a call to a method, whose specific purpose is to modify e.
s+="!"; is not a method call. It is exactly equivalent to this:
s = s + "!";
This does not alter the state of any object. It merely creates a new String object (that is, a String whose text value is the old value of s plus "!"), and assigns that to the variable s. You are changing what s holds, but you didn’t modify the original String object that s used to hold.
It turns out there are no methods of String which will modify the String object, because Strings are immutable, by design. On the other hand, the StringBuilder class exists specifically to create and work with changeable text values.
I have a problem with a program I'm writing for a school assignment.
Essentially, before this piece of code, I already recieve and work with a bunch of information that I store into an array of objects. Now I have to sort this array (after it's sorted, I will have to calculate some things in the order of the PRIORITY variable).
presume I already have a MyClass[] array called input, that stores a finite amount of MyClass objects.
MyClass[] priorityArray = new MyClass[input.length];
for (int i=0; i<priorityArray.length; i++) {
int maxIndex = 0;
int maxPrivilege = input[i].returnPrivilege();
for (int j=1; j<input.legnth; j++) {
int currentPrivilege = input[j].returnPrivilege();
if (currentPrivilege > maxPrivilege) {
maxPrivilege = currentPrivilege;
maxIndex = j;
}
}
priorityArray[i] = input[maxIndex];
input[maxIndex].setPrivilege(-900000000);
}
the MyClass class if nothing fancy, but of course, contains a proper constructor, getter and setter methods and an integer variable "privilege".
I'm getting an error in my final tests of the program and, seeing as the program returns privileges as "-900000000", it has to have something to do with this part of the code.
It's also not even writing certain MyClass instances from the input array into the priorityArray array.
How can I clead this up? Help.
I'll rewrite my answer totally.
In this line
priorityArray[i] = input[maxIndex];
You are assigning object from one array to another array by reference. It means that there is only one object and you set value to -9000000 in the next line to it. Of course element in priorityArray will have the same changes. To fix it you need to clone your object here.
I'm working with two-dimensional array-values that should be inserted into a ArrayList. But this is done in a for-loop and the value of the two-dimensional array-value gets changed as the loop runs since it is just used as an temp-variable (which makes all of the variables stored in the ArrayList gets changed as this variable changes).
So if I try to print out the content of the ArrayList when the loop is done all the values are the same.
for(int i = 0; i <= Counter; i++)
{
if(Xhavetomove >= i)
arrayvalue[0][0] = this.Xspeed;
else
arrayvalue[0][0] = 0;
if(Yhavetomove >= i)
arrayvalue[0][1] = this.Xspeed;
else
arrayvalue[0][1] = 1;
System.out.println(arrayvalue[0][1]);
Object.movement.add(arrayvalue);
}
Are there anyway I can make it store the value itself?
For example: The first time the loop runs the value is "5,5" but if I print out the ArrayList when the loop is done all the values has turned into "5,1".
The problem is the way Array is added to the Object here. You are not adding the Array to the Object. What is happening is you are adding the address to the location in memory where the Array resides. So every time you add the Array to the Object, you are adding the same address every time. So every Array in the Object is actually the same Array over and over since they all point to a single location in memory. So when you change the Array, it will appear to change all of them inside the Object.
The best thing to do is either create a new Array every time through the loop, essentially creating a new location in memory for the Array to reside, or clone() the Array which will create a new reference.
Example:
String[] houseOfStark = {"Eddard", "Catelyn",
"Robb", "Sansa", "Arya", "Bran", "Rickon"}; // Sorry Jon
String[] copyOfStark = houseOfStark;
String[] cloneOfStark = houseOfStark.clone();
houseOfStark[1] = "Lady Catelyn";
System.out.println(houseOfStark[1]);
System.out.println(copyOfStark[1]);
System.out.println(cloneOfStark[1]);
Will produce:
Lady Catelyn
Lady Catelyn
Catelyn
Good blog post explaining the difference
At the end each add needs to create an own object.
To use clone is one way.
Or to add always the values in pairs, in an other.
A totally different way is to use serialization. This make sense when you do not want to calculate this values but to log it. In this case you need an outputStream
What is best is defined by what you want to do with Object.movement
You need to use array's clone() method to make its copy:
//for example
int[][] copy = (int[][])arraySource.clone();
Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}