Considering Java. How are these 2 different and why?
public void languageChecks() {
Integer a = 5;
Integer b = new Integer(5);
change(a); // a doesn't get incremented. value is 5
change(b); // b does. value is now 6
}
public void change(Integer a) {
a++;
}
The only difference is that
Integer b = new Integer(5);
guarantees a new object is created. The first will use an instance from a cache (see Integer.valueOf()).
Both are immutable and the references to both are passed by value (as is everything in Java). So change() has no effect on either.
I'd always been taught a++ was just shorthand for a = a + 1 in which case a local variable is created named a and immediately thrown away when the method returns. There're no methods on Integer that change the value (it's immutable), and likewise no operations on primitive ints that change their value.
Neither call to change() affects the values passed in, because of auto-boxing/unboxing.
public void change(Integer a) {
// This unboxes 'a' into an int, increments it and throws it away
a++;
}
The above code seems to imply that a++ changes the value of a, since it's an object, not a primitive. However, ++ is not overloaded by Integer, so it unboxes it to be able to apply the ++operator on its int. To me the compiler shouldn't allow this.
Related
I have a basic doubt, we can increment reference of Integer class object, while not reference of any other class(D class has 1 Integer data member and one parameterized constructor).
Integer x=new Integer(10); x++;
D d=new D(10); d++;
here both x and d are reference still we are able to increment Integer reference while not any other reference. I am missing something very basic, please help me out.
Integer x=new Integer(10); x++;
Here java compiler will do the un-boxing of the object, which converting the Integer object into primitive int. Then the increment operation will be performed. This is only defied for java primitives, the auto-boxing is converting primitive to wrapper object and reverse of it is call un-boxing. This is what is happening here.
The auto-boxing or un-boxing which is an automatic conversion, it is defined for java primitives only. So it can not be performed on other objects. Remember, the object are not just memory references like C or C++ that we can increment them.
This is because of Autoboxing for wrapper classes which was introduced from jdk 1.5. Internally java will convert the integer reference to int and increment it. You can't increment the objects.
Java has no way of overloading operators for arbitrary classes. Thus, D d; d++ is just not available. You can do:
public class D {
private int value;
public D( int v ){
value = v;
}
public void increment(){
value++;
}
}
Now you can do
D d = new D(10);
d.increment();
and d's value will be 11.
According to Oracle Java Documentation, The automatic conversion of primitive data types into its equivalent wrapper type is known as autoboxing and opposite operation is known as unboxing. Whenever we use object of wrapper class in an expression, automatic unboxing and autoboxing is done by JVM.
Integer object;
object = 100; //Autoboxing of int
++object;
When we perform an increment operation on Integer object, it is first unboxed, then incremented and then again reboxed into Integer type object. You can also take a look at How java auto boxing/unboxing works?
I have a method that accept one parameter of type short.
public void doSomething(short value) {
//DO STUFF
}
And I can call it this way:
short value = 3;
doSomething(value);
But not this another one:
doSomething(3);
Why? Is there a way to denote that this parameter is a short and not an int?
You can call it this way :
doSomething((short)3);
Without casting, 3 will always be an int literal.
The reason
public void doSomething(short value) {
//DO STUFF
}
can be called as
short value = 3;
doSomething(value);
cause value is already short
When you call it like doSomething(3); 3 is considered as integer and cannot be casted to short implicitly.
Basically doSomething(3); would require a
public void doSomething(int value) {
//DO STUFF
}
method to go with.
However you can cast 3 to short and can call the method as:
doSomething((short)3);
In Java, arithmetic expressions on the right hand side of the assignment evaluates to int by default. Look at this surprising example:
short a = 1;
short b = 2;
short c = a + b; // Error!
You need to explicitly cast to short as already mentioned in other answers, or change the method's signature to accept int instead.
It's worth mentioning that in terms of space short takes the same space as int if they are local variables, class variables or even instance variables since in most systems, variables addresses are aligned, I would simply change the signature of the method to accept an int instead and wouldn't complicate things.
This question already has an answer here:
Java method doesn't change parameter objects [duplicate]
(1 answer)
Closed 8 years ago.
Ok. I'm completely aware that all values in Java are passed by value. But this example does not behave as I expected:
public class Test {
private static void changeInteger(Integer x) {
x = 5;
}
public static void main(String[] args) {
Integer x = 0;
changeInteger(x);
System.out.println(x);
}
}
Since I'm passing wrapper class to the changeInteger Method, I'm passing its address, so, after executing function that should affect my x variable and set it to 5. But eclipse says that output is still 0. What did I understand wrong?
Consider this example:
class Wrapper {
int n;
public Wrapper(int k) { n = k; }
public String toString() { return ""+n;}
public static Wrapper valueOf(int k) { return new Wrapper(k); }
}
Now let us replace Integer in your code with the Wrapper class above:
private static void changeInteger(Wrapper x) {
x = Wapper.valueOf(5);
}
public static void main(String[] args) {
Wrapper x = Wrapper.valueOf(0);
changeInteger(x);
System.out.println(x);
}
Since you mentioned that you know about passing by value, I hope that it is clear why this code does what it does.
Now let's go back to your code. Under the hood, it is exactly the same code. The only difference is that you do not call Wrapper.valueOf: the compiler does it for you through autoboxing. Once you realize that this is what is going on, the issue should be clear to you.
ByteCode of changeInteger() to show that Integer.valueOf() is called :
private static void changeInteger(java.lang.Integer);
Code:
Stack=1, Locals=1, Args_size=1
0: iconst_5
1: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
.... // some other code
With x = 5; you assign a new value to x inside changeInteger(). You are not changing the value of the current Integer object.
The value of x outside the method is not affected.
You get puzzled by the autoboxing function of java. You cannot assign a primitive value to an objec. When you call x=5 it creates a new Integer object with 5 value and assignes its reference to x. But this affects only the parameter in the scope of changeIngeger, the original object with 0 and the reference of x in main scope are untouched.
Your problem is the fact that Java is pass-by-value not by-reference so the x in the method is not the same x of main. The fact that Integer is an immutable class, here doesn't change anything.
All Java parameters are passed by value. For all non-primitive types, the value contains a reference to the object that's passed.
For your piece of code, the Integer object is stored at location A in memory. Another location B in memory represents the main's variable x and stores a value A.
For the changeInteger call, a new location C is created and a value in B (which is A) gets copied to it. This is the local x of the changeInteger function.
With the assigning, you create a new variable stored at D and its location is assigned to C. Then you return from the method.
You can see that A and B isn't modified anywhere and thus the value remains unchanged.
Keeping as simple as it is, All Java Wrapper classes are Immutable. So you cannot seeing the change.
If you want to see the change, just return from method (not main) and assign it back.
This is the code I have, please look at it before you read the question
package ict201jansem2012;
public class Qn3b {
public static void main(String[] args) {
int a = 1;
int b[] = {4,5};
String s = "Good luck!";
method1(b[1]);
System.out.println("(1) b[0] = "+b[0]+"; b[1] = "+b[1]);
method2(b);
System.out.println("(2) b[0] = "+b[0]+"; b[1] = "+b[1]);
method3(a);
System.out.println("(3) a = " + a );
method4(s);
System.out.println("(4) s = " + s );
}
public static void method1(int b) {
b = 7;
}
public static void method2(int[] b) {
b[0] = 3;
}
public static void method3(int a) {
a = 3;
}
public static void method4(String s) {
s = "UniSIM";
}
}
Output:
(1) b[0] = 4; b[1] = 5
(2) b[0] = 3; b[1] = 5
(3) a = 1
(4) s = Good luck!
So my question is ,
This is intresting for me to know as learning programmer. The int b array 0 index value has changed, but not the other variables like the String s and int a. Before i ran this program I roughly thought in my mind that the variable will change their values as the methods are called ,this is because the method is being called and the main method vairable such as a,s and b array are passed and then they are being modified.
So in a nutshell why is that the b array 0 index is changed while the other variables are not changed?
Because you said you were a beginner programmer, I'll do a little writeup to explain (or try to explain) exactly what is happening.
It is because you are passing an argument to your method1 - method4 methods
These arguments, themselves, are references to other objects.
When you use the assignment operator, an equals sign, you overwrite that reference for the value in the current scope - where variables can be 'seen'.
In your code:
In the case of method1 you are creating a new reference, the variable can only be seen within that scope. That is, when you then go b = << expr >> you are assigning the variable b within method1's scope the value, not b in the main scope. The same is true of your method3 and method4 methods, you are assigning a new value to the respective variables within that scope, as you are creating new references rather than altering the original objects.
But, method2's code behaves differently, this is because you are mutating the object inside that code. You are altering the object directly - rather than creating a new reference inside that scope.
Consider the code below
int[] array = new int[] {1, 2};
public void test()
{
method1(array);
System.out.println(array[0] + ", " + array[1]);
method2(array);
System.out.println(array[0] + ", " + array[1]);
}
// because we are working with objects, the identifier, can be different to the arrays identifier
// in this case, I've chosen to use 'a' instead of 'array' to show this
public void method1(int[] a)
{
// this mutates the array object
a[0] = 2;
}
public void method2(int[] array)
{
// this overwrites the method2.array but not the global array
array = new int[] { 1, 2, 3 };
}
We create a new array, with identifer 'array' in the global scope. (In Java, this would be the classes own scope)
In method1, we take an argument, which is the same object being passed as the global array object, so when we mutate it, both objects will change. So, the first print statement will be
"2, 2"
Where array[0] has been altered
N.B. Because we dealing with objects, the 'name' of the variable doesn't matter - it will still be a reference to the same object
However, in method2, we take an argument, like in method1, but this time we use the assignment operator to assign that variable to a new value in the scope that it's currently in - so the global array isn't altered, so we still print out
"2, 2"
For a beginner programmer, I would personally write a few test programs where you get to fully understand how variables and scopes work.
But just know, everytime you create a new block of code, a new scope is created, local variables to that scope can only be seen in that scope and ones below it.
For instance:
public void test()
{
int a = 5;
method1(a);
System.out.println(a); // prints 5
}
public void method1(int a)
{
// a is only viewable in the method1 scope
// and any scopes below it, that is, any scopes created within method1
// and since we use an assignment operator, we assign method1.a a value, not global 'a' a value
a = 123;
if (true)
{
// this is a new scope, variables created in this block cannot be seen outside it
// but can see variables from above it
System.out.println(a); // prints 123
}
}
Here, we create a new scope inside method1 inside the if statement, which can see a above it. However, because method1 and test's scopes are both independent, when we use the assignment operator, we assign the value of a to the local scope. So a is different in both test and method1
I hope you understand better now.
I'm not very good at conveying things, but if it even helped a little bit in understanding scopes I did well, plus, it was fun.
Java is pass-by-value, but most values (everything that's not a primitive, in this case int[] and String) are references, which means they act like pass-by-reference.
Here's a nice writeup: http://javadude.com/articles/passbyvalue.htm
arrays are special type of objects and memory will be allocated on HEAP. When you pass array as parameter to method it will be pass as reference-value (copy of the reference).
This means initial b and this new reference points to same object. Unless new reference points to another object, changes on this reference will reflect on same object. That is why you are seeing value reflected on original array.
All of the values were passed TO the inner methods, but the inner methods returned nothing. However, method2 modified the internal value of the array that was passed to it, so that inner value appeared modified on return.
Note that method2 is the only one where you did not assign to the variable (parameter) itself, but rather assigned to an element of the object whose reference was passed in.
There is a critical difference between modifying the reference (pointer) to an object, and modifying the object itself.
I need to convert C code to Java.
The minimal C code is:
void changeX(int *x)
{
*x=5;
}
changeX is called in function B as:
void B()
{
int k= 2;
changeX((int*) &k);
}
The problem while converting it into Java is that x is not a class member so i cannot use this. How can i convert such code to Java?
Assuming you're really asking, "Can I use pass-by-reference in Java" (which that C code isn't using, but is emulating with pointers, which also aren't supported in Java) the answer is no.
Options:
Pass in a reference to an object which does contain a field you can change
(Ugly, but equivalent to the above in some senses) Pass in an array of size 1 constructed using the local variable, mutate the variable in the method, and then set the local variable again based on the array contents afterwards
Return the new value and assign it that way
Change your design so you don't need this
The last two of these options are the nicest ones. If you could give more information about the bigger picture - why you think you want to do this - that would be helpful.
Use one-element array reference:
void changeX(int[] x) {
// do not forget about checks
x[0] = 5;
}
void test() {
int[] x = {0};
changeX(x);
}
Being a primitive, and not a class member, you cannot pass the reference to another method. Use a class member instead.
You should return the new value of x,the method should as follow:
private int changeX(int x){
return 5;
}
You existing C code is incorrect:
void B()
{
int k= 2;
// you are not passing address of variable k but instead
// you are passing k (which is 2) as the address whose location needs
// to be changed. So you are writing to address 2 which you don't own.
changeX((int*) k);
}
What you need is:
changeX(&k);
Now this is changing the value of a variable by passing it by address. Now such a thing is not possible in Java which always uses pass by value. But you can get similar effect by enclosing the int variable inside an Integer object or an integer array (also an object) and pass the object by value.
Simply put Java has no equivalent to a pointer to a basic type - in order to achieve this you need a reference int type something like
class RefInt {
public int Value;
RefInt(int x) { Value=x; }
}
And you pass this in the same context and it works like so:
RefInt X=new RefInt(3)
ChangeX(X);
Obviously in this context simply changing the return value to type int and assigning it would be better but that doesn't solve your general problem.
Option1:
Put the int variable in a wrapper class. Pass that the method. In the method you can change the value in wrapper instance.
Option2:
Make changeX() return int and replace all changeX(k) with k = changeX(k).