I wrote some code to understand what would happen if I store a mixture of primitives, objects mutable or immutable into an Array object. Could I amend them after storage and see if it Dereferenced these things correctly and returned their amended values. I did not get what I had expected my code to do ? I think I know why and would like to clarify whether this understanding is correct. Here is the code.
public class DriverApp3 {
private static String CYEAR = "2014" ;
private static StringBuffer CYEARFLG = new StringBuffer("1914") ;
public double money = 2.13 ;
public static void main(String args[])
{
Integer j = 12 ;
DriverApp3 d = new DriverApp3();
StringBuffer sb = new StringBuffer("Unicorn");
MutableInteger mi = new MutableInteger(67);
int i = 76 ;
Object[] parseXML = new Object[]{j,DriverApp3.CYEAR,d, d.money,DriverApp3.CYEAR, sb, mi, DriverApp3.CYEARFLG,i};
// 0 1 2 3 4 5 6 7 8
System.out.println("======chng of all original values ==========");
j = 13 ;
d.money = 3.14 ;
parseXML[4]="2015";
DriverApp3.CYEAR = "2013";
mi.set(9);
sb.replace(3,5,"KO");
DriverApp3.CYEARFLG.replace(0,4,"1939");
i = 7 ;
Object[] chngdO = new Object[]{j,DriverApp3.CYEAR,d, d.money,DriverApp3.CYEAR, sb, mi, DriverApp3.CYEARFLG,i};
int cnt = 0 ;
for (Object m : parseXML)
{
Integer s_objid = m.hashCode();
String clsType = "Type="+m.getClass().getTypeName();
String clsName = "SimplName="+m.getClass().getSimpleName();
String canName = "CanonName="+m.getClass().getCanonicalName();
Object n = chngdO[cnt];
Integer ns_objid = n.hashCode();
String nclsType = "Type="+n.getClass().getTypeName();
String nclsName = "SimplName="+n.getClass().getSimpleName();
String ncanName = "CanonName="+n.getClass().getCanonicalName();
System.out.println(cnt + ": Hashcode=" + s_objid + ":" + clsType + ":" + m + "\n " + ": Hashcode=" + ns_objid + ":" + nclsType /*+ ":"+ clsName+ ":"+ canName*/+ ":" + n + "\n" );
cnt++ ;
}
}
#Override
public String toString()
{
return "Hashcode="+this.hashCode() + "," + DriverApp3.CYEAR ;
}
}
The mutable class is also here .....
/**
*
* #author code snippet from stackoverflow.com
* Not thread safe
*/
public class MutableInteger {
private int value;
public MutableInteger(int value) {
this.value = value;
}
public void set(int value) {
this.value = value;
}
public int intValue() {
return value;
}
public String toString()
{
return "id="+this.hashCode()+" val=" + this.value ;
}
}
The output of my application is .....
======chng of all original values ==========
0: Hashcode=12:Type=java.lang.Integer:12
: Hashcode=13:Type=java.lang.Integer:13
1: Hashcode=1537249:Type=java.lang.String:2014
: Hashcode=1537248:Type=java.lang.String:2013
2: Hashcode=366712642:Type=xander.DirRefOrCopy.DriverApp3:Hashcode=366712642,2013
: Hashcode=366712642:Type=xander.DirRefOrCopy.DriverApp3:Hashcode=366712642,2013
3: Hashcode=815979831:Type=java.lang.Double:2.13
: Hashcode=300063655:Type=java.lang.Double:3.14
4: Hashcode=1537250:Type=java.lang.String:2015
: Hashcode=1537248:Type=java.lang.String:2013
5: Hashcode=1829164700:Type=java.lang.StringBuffer:UniKOrn
: Hashcode=1829164700:Type=java.lang.StringBuffer:UniKOrn
6: Hashcode=2018699554:Type=xander.DirRefOrCopy.MutableInteger:id=2018699554 val=9
: Hashcode=2018699554:Type=xander.DirRefOrCopy.MutableInteger:id=2018699554 val=9
7: Hashcode=1311053135:Type=java.lang.StringBuffer:1939
: Hashcode=1311053135:Type=java.lang.StringBuffer:1939
8: Hashcode=76:Type=java.lang.Integer:76
: Hashcode=7:Type=java.lang.Integer:7
Index 0
For the Integer j, it is immutable, so as soon as I amend it outside the array the 0th one is still pointing to the one with value 12 since it is still alive on wherever Java keeps it's immutable single copy for that Integer. This is apparently an area where all runtime constants for each class or interface is kept. In this case it is the String literal area. The amended j is pointing to a new Immutable single copy of value 13. See Hashcodes differ as well.
Index 1
Same issue like above. Just because it is a member of DriverApp3 you would have expected to have amended itself but it does not because the array has stored an old value of the memory address String in wherever java stores the single copy of that immutable. Since, that address is still "alive" it keeps pointing to that memory address within the array. Very very unintuitive - not sure whether there are other patterns or languages that handle this better. It could be a source of error. Want to make sure you reflect your changes then - use MUTABLE objs within it instead of IMMUTABLE. Or, you have the additional thinking overhead of having to remember that Java might Autobox your primitive (if you were storing a primitive ) into an Object literal depending on whether it is a String, Integer, Double etc.
Index 2
Everything works as expected - it is pointing to the array. So, it continues to point to the same mutable object address when it was changed.
Index 3
Again the double gets Autoboxed into a immutable Double. So, it is the same issue like String and Integer because it is an Object Array. Surely, been like this since Java 1 - btw - I am using Java 8 compiler here.
Index 4
parseXML[4]="2015";
Well here we are directly overwriting the address with the address of the immutable String literal 2015
Index 5 & 6
StringBuffer and MutableInteger reflect amendments correctly because they still point to the same address. Java does not create a new copy because they are meant to mutable by the very nature of they have been defined.
Index 7
Reflects the changes because it is a mutable StringBuffer and not a shared immutable literal !!
Index 8
Suffers from the same issue of a primitive being autoboxed into a immutable shared single copy literal.
So, if you want the contents of your stored Array to reflect your amended changes outside of the array use Mutable Objects. And, beware of the trap of automatic Autoboxing into immutable Object literals.
Related
I know this is probably very stupid, but a lot of places claim that the Integer class in Java is immutable, yet the following code:
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
Executes without any trouble giving the (expected) result 6. So effectively the value of a has changed. Doesn't that mean Integer is mutable?
Secondary question and a little offtopic: "Immutable classes do not need copy constructors". Anyone care to explain why?
Immutable does not mean that a can never equal another value. For example, String is immutable too, but I can still do this:
String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"
str was not changed, rather str is now a completely newly instantiated object, just as your Integer is. So the value of a did not mutate, but it was replaced with a completely new object, i.e. new Integer(6).
a is a "reference" to some Integer(3), your shorthand a+=b really means do this:
a = new Integer(3 + 3)
So no, Integers are not mutable, but the variables that point to them are*.
*It's possible to have immutable variables, these are denoted by the keyword final, which means that the reference may not change.
final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.
You can determine that the object has changed using System.identityHashCode() (A better way is to use plain == however its not as obvious that the reference rather than the value has changed)
Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
prints
before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda
You can see the underlying "id" of the object a refers to has changed.
To the initial question asked,
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
Integer is immutable, so what has happened above is 'a' has changed to a new reference of value 6. The initial value 3 is left with no reference in the memory (it has not been changed), so it can be garbage collected.
If this happens to a String, it will keep in the pool (in PermGen space) for longer period than the Integers as it expects to have references.
Yes Integer is immutable.
A is a reference which points to an object. When you run a += 3, that reassigns A to reference a new Integer object, with a different value.
You never modified the original object, rather you pointed the reference to a different object.
Read about the difference between objects and references here.
Immutable does not mean that you cannot change value for a variable. It just means that any new assignment creates a new object ( assigns it a new memory location) and then the value gets assigned to it.
To understand this for yourself, perform Integer assignment in a loop ( with integer declared outside the loop ) and look at the live objects in memory.
The reason why copy constructor is not needed for immutable objects is simple common sense. Since each assignment creates a new object, the language technically creates a copy already, so you do not have to create another copy.
This is how I understand immutable
int a=3;
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8
If int could mutate, "a" would print 8 but it does not because it is immutable, thats why it is 3. Your example is just a new assignment.
"Immutable classes do not need copy constructors". Anyone care to explain why?
The reason is that there is rarely any need to copy (or even any point in copying) an instance of a immutable class. The copy of the object should be "the same as" the original, and if it is the same, there should be no need to create it.
There are some underlying assumptions though:
It assumes that your application does not place any meaning on the object identity of instances of the class.
It assumes that the class has overloaded equals and hashCode so that a copy of an instance would be "the same as" the original ... according to these methods.
Either or both of those assumptions could be false, and that might warrant the addition of a copy constructor.
I can make clear that Integer (and other of its creed like Float, Short etc) are immutable by simple sample code:
Sample Code
public class Test{
public static void main(String... args){
Integer i = 100;
StringBuilder sb = new StringBuilder("Hi");
Test c = new Test();
c.doInteger(i);
c.doStringBuilder(sb);
System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
}
private void doInteger(Integer i){
i=1000;
}
private void doStringBuilder(StringBuilder sb){
sb.append(" there");
}
}
Actual Result
The result comes to he Hi There 100 instead of expected result (in case of both sb and i being mutable objects) Hi There 1000
This shows the object created by i in main is not modified, whereas the sb is modified.
So StringBuilder demonstrated mutable behavior but not Integer.
So Integer is Immutable. Hence Proved
Another code without only Integer:
public class Test{
public static void main(String... args){
Integer i = 100;
Test c = new Test();
c.doInteger(i);
System.out.println(i); //Expected result is 1000 in case Integer is mutable
}
private void doInteger(Integer i){
i=1000;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1="Hi";
String s2=s1;
s1="Bye";
System.out.println(s2); //Hi (if String was mutable output would be: Bye)
System.out.println(s1); //Bye
Integer i=1000;
Integer i2=i;
i=5000;
System.out.println(i2); // 1000
System.out.println(i); // 5000
int j=1000;
int j2=j;
j=5000;
System.out.println(j2); // 1000
System.out.println(j); // 5000
char c='a';
char b=c;
c='d';
System.out.println(c); // d
System.out.println(b); // a
}
Output is :
Hi
Bye
1000
5000
1000
5000
d
a
So char is mutable , String Integer and int are immutable.
Copy and run this code,I hope this will answer all your doubts
private static void wrapperClassDemo() {
//checking wrapper class immutability using valueOf method
//We can create wrapper class by using either "new" keyword or using a static method "valueOf()"
//The below Example clarifies the immutability concept of wrapper class in detail
//For better understanding just ciopy the below code to the editor and run
Integer num1 =Integer.valueOf(34); // i'm passing the 34 as the parameter to the valueOf method
System.out.println("value assigned to num1 is : "+num1);
System.out.println("Printing the hashcode assigned to store the \" num1 \"value in memory: "+System.identityHashCode(num1));
Integer num2 =Integer.valueOf(34);
System.out.println("value assigned to num2 is : "+num2);
System.out.println("Printing the hashcode assigned to store the \" num2 \"value in memory: "+System.identityHashCode(num2));
/*Now u can notice both the hashcode value of num1 and num2 are same. that is because once you created the num1 with the value 34 an object is
* created in the heap memory. And now You are passing the value same as num1 to the num2 .Now JVM Checks the same value is present in the heap Mmeomry
* If present the reference variable(in this example it is num2) will be pointed to the same address where the object num1 is stored so u get the same hashcode */
num2++; // You can use num2 = 35 as both are same;
System.out.println("\nvalue assigned to num2 is : "+num2);
System.out.println("Printing the hashcode of \" num1 \": "+System.identityHashCode(num1) + "\nPrinting the hashcode of \" num2 \": "+System.identityHashCode(num2));
System.out.println("As now you can notice the hashcode has changed for num2 ,That is because now a new object is created for num2 and it is referencing the new object");
//Again i'm incrementing num2
System.out.println("\nBefore incremeting the hashcode of \" num2 \" is: "+System.identityHashCode(num2));
num2++; // You can use num2 = 36 as both are same;
System.out.println("After incremeting the hashcode of \" num2 \" is: "+System.identityHashCode(num2));
//now the hashcode value of num2 is changed ,again new object is created for the updated value and num2 is referencing new object ,and old object will be garbage collected
System.out.println("\n Thus the CONCLUSION is Wrapper objects are immutable ,They only create new object and refernce the new object ,They won't modify the present object ");
System.out.println("This is applicable for Strings also");
Something to hold in mind is that there is now a cache for Integer values. It sometimes saves developers from the mistake of using == instead of .equals() when changing from int to Integer. Not always though. When you instantiate a new Integer, there will be a new instance created. So Integers are not only immutable, but also semi static.
Integer a = 3;
Integer b = 3;
Integer c = new Integer(3);
b = b + 1;
b = b - 1;
System.out.println("a-id: " + System.identityHashCode(a));
System.out.println("b-id: " + System.identityHashCode(b));
System.out.println("c-id: " + System.identityHashCode(c));
System.out.println("a == b: " + (a == b));
System.out.println("a == c: " + (a == c));
System.out.println("a eq c: " + (a.equals(c)));
Gives the printout:
a-id: 666988784
b-id: 666988784
c-id: 1414644648
a == b: true
a == c: false
a eq c: true
I am currently learning Java, and I'm trying to understand the logic behind math in Java. On old tests in this course, there have been problems like the ones below. I am then supposed to write out what this code is going to display. My problem is that I don't understand two of the numbers in both codes.
In the first test class, the integer Tal prints out as 15. Ok, I can follow the logic there.
It goes like this:
c.setNbrOf(4+1) = 5
int tal = c.getNbrOf()+10 = 15
BUT
When I apply the same logic to the second test class I get the wrong answer.
My logic goes:
c.setNbrOf(4+1) = 5
c2.setNbrOf(5) +1 = 6
Since Customer c = c2, this means c also has the value of 6 (?)
So, int tal = 6 + 5 which is 11.
It's not though. When I run it, it's 12.
Why does the ++tal in the method andra affect its value globally? I thought it was only local.
I hope I haven't been to unclear.
The customer class is needed to run the test class.
public class Customer {
private String name;
private int nbrOf;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name=name;
}
public int getNbrOf() {
return this.nbrOf;
}
public void setNbrOf (int nbrOf) {
this.nbrOf=nbrOf;
}
}
The first test class.
public class Test {
public static void main(String[] args) {
Customer c = new Customer();
c.setName("Kund1");
c.setNbrOf(4+1);
int tal = c.getNbrOf()+10;
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf());
foo(c, tal+3);
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf());
System.out.println("Tal: "+tal);
}
public static void foo(Customer p, int x) {
p.setName("Kund2");
p.setNbrOf(x);
x ++;
}
}
The second.
public class Test {
public static void main(String[] args) {
Customer c = new Customer();
c.setName("K1");
Customer c2 = c;
c.setNbrOf(4+1);
c2.setNbrOf(c.getNbrOf()+1);
int tal = c.getNbrOf()+5;
System.out.println("Namn: "+c.getName()+" ålder: "+c2.getNbrOf());
andra(c, ++tal);
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf()+",
"Tal: "+tal);
}
public static void andra(Customer p, int tal) {
p.setName("K2");
tal=9;
p.setNbrOf(tal);
}
}
When you write ++tal, it means tal = tal + 1; then return the new value of tal as a result. Hence, when you pass ++tal to a function, you have run two commands.
Also, you should be aware that setting value of tal inside andra function, is local and not changed the value of tal outside the function. Hence, the final value of tal after calling andra(c, ++tal) would be 12.
[EDIT] Fixed the incorrect part about pass by value and clone()
You are asking two questions so let's attach each one separately.
A) What is the value of c and c2 at specific points in the code.
To answer this you need to realize that just saying 'c = c2' doesn't tell the full story. You first create two instances of the Customer object and store the references to them in c and c2 respectively. When you assign c = c2 you are making both variable store the reference to the same (single) instance of Customer; the other will get garbage collected. Now, it is possible to change the state of the remaining object through method calls to either c OR c2 because they both refer to the same instance.
This means that
c.setNbrOf(4+1); // AAA
c2.setNbrOf(c.getNbrOf()+1); // BBB
changes the value of the same nbrOf member variable twice, it just looks like they are separate because you have made c an alias of c2 (or vice versa depending on how you want to look at it). After line AAA c.nbrOf does equal 5; to calculate what happens in line BBB you need to break the line up into its parts. Calling c2.setNbrOf() with an argument that is actually an expression of the sum of two things, the result of a call to c.getNbrOf() and the numeric literal '1'. The call to c.getNbrOf() returns 5 and the expression adds 1 to it before passing the result, 6, to the call of c2.setNbrOf(). Since c and c2 are aliases of each other you will get a result of '6' when you call getNbrOf using either c or c2 simply because they both point to the same instance.
B) Why does the ++tal in the method andra affect it's value globally?
Well, it doesn't affect the value globally, it only looks that way because again, you have run into an expression used as an argument to a method.
andra(c, ++tal); // CCC
The call to andra() does not pass '++tal' into the method, it evaluates the expression first, which actually increments tal by 1 in the local scope and then evaluates the value of tal to determine the value to be sent to the method call. This means that, yes, tal was 11 before the line CCC but during the evaluation of the arguments the variable's value was changed to 12 before the call is made. So why does the code print '12' when you can clearly see that
public static void andra(Customer p, int tal) {
p.setName("K2");
tal=9; // DDD
p.setNbrOf(tal);
}
line DDD should result in the value of p.nbrOf being 9? Well, yes, the value of p.nbrOf does get changed to '9' in the line following DDD, just as p.name gets changed to "K2". This leads to your question of why the code prints '12' instead of '9'. This is because of another thing you have to consider and that is scope. The method andra() actually creates a new storage location named 'tal' that is not the same location as the variable with the same name in main(), that is andra() is hiding the name 'tal' so that when it changes the value of 'tal' to 9 it is only changing the local variable and not the variable with the same name in the calling code.
I have to say that this sample code is doing several things to trip you up, which also means it's doing its job to help you understand the different ways the language handles its symbol table that can be confusing. The sample code isn't making it any better by using tal as a local variable in the test code AND as a parameter name in the methods, that is a poor practice but was used here to make the exercise more difficult.
Try this code to see what is actually happening.
// actually Test3 would be a better name, but I'll leave that to you
public class Test {
public static void main(String[] args) {
Customer c = new Customer();
c.setName("K1");
Customer c2 = c;
c.setNbrOf(4+1);
c2.setNbrOf(c.getNbrOf()+1);
int tal = c.getNbrOf()+5;
int tal2 = ++tal;
System.out.println("Namn: "+c.getName()+" ålder: "+c2.getNbrOf()+" reference to c:"+ c);
andra(c, tal2);
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf()+",
Tal: "+tal);
}
public static void andra(Customer p, int tal3) {
p.setName("K2");
tal3=9;
System.out.println("BEFORE - reference to p: "+p+" tal: "+tal3+" p.nbrOf:"+p.getNbrOf());
p.setNbrOf(tal3);
System.out.println("AFTER - reference to p: "+p+" tal: "+tal3+" p.nbrOf:"+p.getNbrOf());
}
}
This should show several things, the reference to p should be a different value than the reference held in c, using unique variable and parameter names should make it clearer about which variables are being evaluated or changed, and moving the ++tal expression to outside the method call should show how the variable is not being changed from within andra().
c = c2 - this line means that from now you want c to point to the same space in memory that holds c2. From now all changes in c or c2 will affect in the same change in the value of the other one (two different refferences point to the same object)
andra(c, ++tal);
is:
tal = tal + 1; //12
andra(c, tal);
andra(c, ++tal); is the same as:
tal = tal + 1;
andra(c, tal);
While andra(c, tal++); is similar to:
andra(c, tal);
tal = tal + 1;
The pre-increment and post-increment operators increment the value prior to (pre) or after (post) evaluating the expression. This is not a "local" vs "global" scope. It affects the scope of the variable that is within scope.
Also, in your andra method, you are explicitly setting tal = 9 so it ignores the passed argument.
since we actually only have one object here, we could ignore OO here and write it in plain math:
if c2 = c, then there is only one object, therefore only one NbrOf
c.setNbrOf(4+1);
NbrOf = 4 + 1 = 5
c2.setNbrOf(c.getNbrOf()+1);
NbrOf = NbrOf + 1 = 5 + 1 = 6
int tal = c.getNbrOf()+5;
int tal = NbrOf + 5 = 6 + 5 = 11;
andra(c, ++tal);
this increases tal by 1 and assigns that value to tal, its equivalent to
tal = tal + 1;
andra(c, tal);
however, the tal inside of andra(c, tal); is an copied value (all primitives are passed by copy, not by reference. So assigning tal=9 wont affect the outside tal! Rename it inside andra(c, tal); to make it easier to understand.
conclusion, tal = 12
Say, for example, I have a double variable in Java:
double alpha = 3;
However, I wanted to create a String variable, including that Double Variable:
String beta = "Alpha has a value of " + alpha;
So that the output would be
//Output
Alpha has the value of 3
However, it will not let me do so, as it says the double value cannot be included in the string value.
As I am doing this for around 150 variables, I want to know how to do it the simplest and shortest way.
Thanks
I am doing this for around 150 variables
A common way of simplifying a repeated task is defining a helper method for it:
String description(String name, Object obj) {
return name + " has a value of " + obj;
}
Now you can use it like this:
String beta = description("Alpha", alpha);
Doing this for 150 variables sounds suspicious - chances are, you have an opportunity to make an array. You can define an array of names, then pair them up with values, like this:
String[] names = new String[] {
"Alpha", "Beta", "Gamma", ...
}
double[] values = new double[] {
1.2, 3.4, 5.6, ...
}
for (int i = 0 ; i != names.length() ; i++) {
System.out.println(description(names[i], values[i]));
}
You can use Double.toString(double).
String beta = "Alpha has a value of " + Double.toString(alpha);
When you need to convert a double to a string, use
Double.toString(double);
Where double is the name of the variable.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is Java “pass-by-reference”?
I am trying to understand the difference between the 2 Java programs written below:
public class Swapping {
public static void main(String[] args) {
IntWrap i = new IntWrap(10);
IntWrap j = new IntWrap(20);
swap(i, j);
System.out.println("i " + i.i + ", j " + j.i);
}
public static void swap(IntWrap i , IntWrap j){
int x = i.i;
i.i = j.i;
j.i = x;
System.out.println("i " + i.i + ", j " + j.i);
}
}
public class IntWrap {
int i;
public IntWrap(int i){
this.i = i;
}
}
Output :
i 20, j 10
i 20, j 10
And second one:
public class Swapping {
public static void main(String[] args) {
Integer i = new Integer(10);
Integer j = new Integer(20);
swap(i, j);
System.out.println("i " + i + ", j " + j);
}
public static void swap(Integer i , Integer j){
Integer temp = new Integer(i);
i = j;
j = temp;
System.out.println("i " + i + ", j " + j);
}
}
Output :
i 20, j 10
i 10, j 20
I am not able to understand that I even though I am passing the Integer object, it should get swapped in the original program. What difference did it created if I wrote the wrapper class on the top of it as I am again passing the object only.
All method parameters, including object references, are passed by value in Java. You can assign any value to the method parameter - the original value in the calling code will not be modified. However you can modify the passed object itself and the changes will persist when the method returns.
There are old Holder classes in J2SE API, specially designed to support calls to methods with "returnable parameters" (IntHolder or StringHolder, for instance). They are mostly used with generated code from IDL language as IDL requires support for in, out and inout parameters. These holders are very uncommon in other code.
You can also simulate passing by reference by using arrays:
String [] a = new String[1]; String [] b = new String[1];
void swap(String [] a, String [] b) {
String t = a[0]; a[0] = b[0]; b[0] = t;
}
Java uses call-by-value to pass all arguments.When you pass the object to a function, the object reference(address of object) gets passed by value.In the second program swap, you are assigning i=j and j=temp.
So i=address of 20
j=address of 10(new object)
But after return from swap, in the main program i is still pointing to 10 and j is pointing to 20.Thats why you are getting 10 and 20 back in main program.
But in first program, you are passing the address of your objects to swap function and in the swap function you are modifying the content of object pointed by these addresses.That is why, it is getting reflected in main method.
Ups. Integer objects are immutable in Java. You can not change their internal values neither from other method, neither at all. Only create new Integer object.
(If you don't know about pointers and references I suggest you go over them a bit, then the world will make more sense - Intro to Pointers)
Putting it down to the most simplest explanation, there are 2 ways java passed everything back and forth:
Pass-by=Value: Used for immutable objects (String, Integer, Double, etc.). These values cannot change with one exception, if you recreate the object.
String x = "World"; <- String x = new String("World");
x = "Hello"; <- x = new String("Hello");
x = x + " World"; <- x = new String("Hello" + " World");
printOutString(x); <- printOutString("Hello World");
Held at one memory location. Any alteration creates a new object with no relation to the previous and look at a separate memory location.
Pass-by-reference: Used for non-immutable objects (Classes, int, double, etc.). These values can be changed and still keep their old place in memory.
int i = 1;
i = 2; <- value at <reference-to-memory-as-value> = 2;
i = i + 1; <- value at <reference-to-memory-as-value> + 1;
printOutInteger(i); <- printOutInteger(value at <reference-to-memory-as-value>);
Any change to this object is done to the memory location. Therefore the location never changes (unless you create a new object).
The same is happening in your programs. The objects that say one thing in the method, then revert to the previous values. You are, in a way, Operator Overloading. You assign new values to the objections (Integer in this case) that you are sending, BUT you have passed the values which means Integer i within the method, because Integer is immutable, is looking at a different memory location to the Integer i in the main method. Therefore, when the method exits, the objects you passed are disposed of and Integer i and j now look at their original memory locations.
When you passed the classes with the int objects, as they are NOT immutable the memory locations were passed (by value) and the values at those locations were worked with. That is why the changes here were shown in the original objects.
I hope this helps
How do I multiply 10 to an Integer object and get back the Integer object?
I am looking for the neatest way of doing this.
I would probably do it this way:
Get int from Integer object, multiply it with the other int and create another Integer object with this int value.
Code will be something like ...
integerObj = new Integer(integerObj.intValue() * 10);
But, I saw a code where the author is doing it this way: Get the String from the Integer object, concatenate "0" at the end and then get Integer object back by using Integer.parseInt
The code is something like this:
String s = integerObj + "0";
integerObj = Integer.parseInt(s);
Is there any merit in doing it either way?
And what would be the most efficient/neatest way in general and in this case?
With Java 5's autoboxing, you can simply do:
Integer a = new Integer(2); // or even just Integer a = 2;
a *= 10;
System.out.println(a);
The string approach is amusing, but almost certainly a bad way to do it.
Getting the int value of an Integer, and creating a new one will be very fast, where as parseInt would be fairly expensive to call.
Overall, I'd agree with your original approach (which, as others have pointed out, can be done without so much clutter if you have autoboxing as introduced in Java 5).
The problem with the second way is the way Strings are handled in Java:
"0" is converted into a constant String object at compile time.
Each time this code is called, s is constructed as a new String object, and javac converts that code to String s = new StringBuilder().append(integerObj.toString()).append("0").toString() (StringBuffer for older versions). Even if you use the same integerObj, i.e.,
String s1 = integerObj + "0";
String s2 = integerObj + "0";
(s1 == s2) would be false, while s1.equals(s2) would be true.
Integer.parseInt internally calls new Integer() anyway, because Integer is immutable.
BTW, autoboxing/unboxing is internally the same as the first method.
Keep away from the second approach, best bet would be the autoboxing if you're using java 1.5, anything earlier your first example would be best.
The solution using the String method is not so good for a variety of reasons. Some are aesthetic reasons others are practical.
On a practical front more objects get created by the String version than the more normal form (as you have expressed in your first example).
On an aesthetic note, I think that the second version obscures the intent of the code and that is nearly as important as getting it to produce the result you want.
toolkit's answer above is correct and the best way, but it doesn't give a full explanation of what is happening.
Assuming Java 5 or later:
Integer a = new Integer(2); // or even just Integer a = 2;
a *= 10;
System.out.println(a); // will output 20
What you need to know is that this is the exact same as doing:
Integer a = new Integer(2); // or even just Integer a = 2;
a = a.intValue() * 10;
System.out.println(a.intValue()); // will output 20
By performing the operation (in this case *=) on the object 'a', you are not changing the int value inside the 'a' object, but actually assigning a new object to 'a'.
This is because 'a' gets auto-unboxed in order to perform the multiplication, and then the result of the multiplication gets auto-boxed and assigned to 'a'.
Integer is an immutable object. (All wrapper classes are immutable.)
Take for example this piece of code:
static void test() {
Integer i = new Integer(10);
System.out.println("StartingMemory: " + System.identityHashCode(i));
changeInteger(i);
System.out.println("Step1: " + i);
changeInteger(++i);
System.out.println("Step2: " + i.intValue());
System.out.println("MiddleMemory: " + System.identityHashCode(i));
}
static void changeInteger(Integer i) {
System.out.println("ChangeStartMemory: " + System.identityHashCode(i));
System.out.println("ChangeStartValue: " + i);
i++;
System.out.println("ChangeEnd: " + i);
System.out.println("ChangeEndMemory: " + System.identityHashCode(i));
}
The output will be:
StartingMemory: 1373539035
ChangeStartMemory: 1373539035
ChangeStartValue: 10
ChangeEnd: 11
ChangeEndMemory: 190331520
Step1: 10
ChangeStartMemory: 190331520
ChangeStartValue: 11
ChangeEnd: 12
ChangeEndMemory: 1298706257
Step2: 11
MiddleMemory: 190331520
You can see the memory address for 'i' is changing (your memory addresses will be different).
Now lets do a little test with reflection, add this onto the end of the test() method:
System.out.println("MiddleMemory: " + System.identityHashCode(i));
try {
final Field f = i.getClass().getDeclaredField("value");
f.setAccessible(true);
f.setInt(i, 15);
System.out.println("Step3: " + i.intValue());
System.out.println("EndingMemory: " + System.identityHashCode(i));
} catch (final Exception e) {
e.printStackTrace();
}
The additional output will be:
MiddleMemory: 190331520
Step2: 15
MiddleMemory: 190331520
You can see that the memory address for 'i' did not change, even though we changed its value using reflection.
(DO NOT USE REFLECTION THIS WAY IN REAL LIFE!!)