This question already has an answer here:
Primitives/Objects Declaration, default initialization values
(1 answer)
Closed 7 years ago.
I have two different programs, the one that uses int and the other Double.
For the below code am getting NullpointerException
public class Solution {
Double cost;
void addTax(Double b)
{
cost+=b;
}
public static void main(String[] args)
{
new Solution().addTax(30.00);
}
}
But for the below code that uses int isn't getting any runtime error.
public class Solution {
int cost;
void addTax(int b)
{
cost+=b;
}
public static void main(String[] args)
{
new Solution().addTax(30);
}
}
So how does that possible? Please explain me.
A primitive (such as int) gets a default value of 0, while a reference type (such as Double) gets a default value of null.
Therefore cost+=b; throws a NullPointerException in the first code snippet (since it's equivalent to cost = cost.doubleValue() + b;), while in the second snippet it is equivalent to cost = 0 + b;, which is fine.
Double is a wrapper over double. Since Double will be set to null when your class's instance is initialized, trying to increment its value (which involves unboxing from Double to double will cause NPE.
Default value of int is 0, so no NPE Hurray :)
In first example you're using class Double and in second one just primitive type int. My guess is that you did it by mistake and you probably you just wanted to use primitive type 'double'
Related
I would like to pass a reference to a primitive type to a method, which may change it.
Consider the following sample:
public class Main {
Integer x = new Integer(42);
Integer y = new Integer(42);
public static void main(String[] args) {
Main main = new Main();
System.out.println("x Before increment: " + main.x);
// based on some logic, call increment either on x or y
increment(main.x);
System.out.println("x after increment: " + main.x);
}
private static void increment(Integer int_ref) {
++int_ref;
}
}
The output running the sample is:
x Before increment: 42
x after increment: 42
Which means int_ref was past to the function by value, and not by reference, despite my optimistic name.
Obviously there are ways to work around this particular example, but my real application is way more complex, and in general one would imagine that a "pointer" or reference to integer would be useful in many scenarios.
I've tried to pass Object to the function (then casting to int), and various other methods, with no luck. One workaround that seems to be working would be to define my own version of Integer class:
private static class IntegerWrapper {
private int value;
IntegerWrapper(int value) { this.value = value; }
void plusplus() { ++value; }
int getValue() { return value; }
}
Doing this, and passing a reference to IntegerWrapper does work as expected, but to my taste it seems very lame. Coming from C#, where boxed variable just remain boxed, I hope I just miss something.
EDIT:
I would argue my question isn't a duplicate of Is Java "pass-by-reference" or "pass-by-value"?, as my question isn't theoretical, as I simply seek a solution. Philosophically, all method calls in all languages are pass-by-value: They either pass the actual value, or a reference to the value - by value.
So, I would rephrase my question: What is the common paradigm to workaround the issue that in java I'm unable to pass a reference to an Integer. Is the IntegerWrapper suggested above a known paradigm? Does a similar class (maybe MutableInt) already exist in the library? Maybe an array of length 1 a common practice and has some performance advantage? Am I the only person annoyed by the fact he can store a reference to any kind of object, but the basic types?
Integer is immutable, as you may notice.
Your approach with private static class IntegerWrapper is correct one. Using array with size 1 is also correct, but in practice I have never seen using array for this case. So do use IntegerWrapper.
Exactly the same implementation you can find in Apache org.apache.commons.lang3.mutable.MutableInt.
In your example you also can provide Main instance to the static method:
public class Main {
private int x = 42;
public static void main(String[] args) {
Main main = new Main();
incrementX(main);
}
private static void incrementX(Main main) {
main.x++;
}
}
And finally, from Java8 you could define an inc function and use it to increment value:
public class Main {
private static final IntFunction<Integer> INC = val -> val + 1;
private int x = 42;
public static void main(String[] args) {
Main main = new Main();
main.x = INC.apply(main.x);
}
}
We already know that the return type of Math.lang() function in java is double.
class Lossy {
public static void main(String args[]) {
int sum;
sum=Math.pow(2,3);
System.out.println (sum);
}
}
Now this statement results in possible lossy conversion error because the variable is of type int and Math.pow() return a double value i.e. 8.0 which is fair enough.
Now look at the code below with some changes.
class Lossy {
public static void main(String args[]) {
int sum=2;
sum+=Math.pow(2,3);
System.out.println (sum);
}
}
Now if we compile this code we don't get an error of possible conversion error, which we should get because we are storing a double value in an integer variable. Moreover, when we are printing the value it shows an integer value. Why?
In the first code, you are assigning a double value to a integer variable. since double value needs 8 bytes whereas integer needs only 4 bytes of memory. We cant store a 8 bytes value into a 4 bytes variable. That's why it shows possible loss of conversion error.
class Lossy
{
public static void main(String args[])
{
int sum;
sum=Math.pow(2,3); //Assigning double value to a int variable. its an Error
System.out.println (sum);
}
}
In the second example you are not simply or directly assigning a value to a integer variable. but you used an add and assign operator(+=), which functions as follows:
sum+=Math.pow(2,3) is equal to sum = sum + Math.pow(2,3);
When you do like the above one, JVM performs Automatic Type Conversion(double to int) or Parsing for the function Math.pow() and it converts the return value of the function to int while compilation. So it works fine. I hope you understand. Thanks!
In Java, consider the following piece of code:
int myPrimitiveInt = 5;
Integer myObjectInt = 4;
Object fromPrimitive = myPrimitiveInt;
Object fromObject = myObjectInt;
System.out.println(fromPrimitive.getClass());
System.out.println(fromObject.getClass());
System.out.println(int.class);
And the output:
class java.lang.Integer
class java.lang.Integer
int
What I would like, is a way to also get the output int for the first println.
WHY?, you will ask. Well, for one thing, I would just like to know if something like this is even possible.
But the actual practical reason behind this is an abstraction layer for testing private methods with primitive type arguments via reflection. The minimal code:
package testing;
import java.lang.reflect.Method;
public class Testing {
private static void doStuff(int a) {
System.out.println("primitive: " + ((Object) a).getClass());
}
public static void main(String[] args) throws ReflectiveOperationException {
Reflect.reflect(Testing.class, "doStuff", 10);
}
}
abstract class Reflect {
static Object reflect(Class<?> clazz, String methodName, Object arg) throws ReflectiveOperationException {
Method method = clazz.getDeclaredMethod(methodName, arg.getClass());
method.setAccessible(true);
return method.invoke(null, arg);
}
}
The output:
Exception in thread "main" java.lang.NoSuchMethodException: testing.Testing.doStuff(java.lang.Integer)
at java.lang.Class.getDeclaredMethod(Class.java:2130)
at testing.Reflect.reflect(Testing.java:17)
at testing.Testing.main(Testing.java:11)
Expected output:
primitive: class java.lang.Integer
Or even better (if possible at all):
primitive: int
Note: I know I can do clazz.getDeclaredMethod(methodName, int.class). The whole point of this post is to make this procedure more abstract. Please do not give me answers suggesting to pass the argument types to the reflect method!
What happens when you write Object x = 10
The int is autoboxed, which makes it into an Integer with value 10.
Why can't this be detected afterwards
Because there is no difference between the Integer with value 10 that was autoboxed and another Integer with value 10
How can I get around this
You need to add separate methods to overload for primitive values, these can handle the primitive values, so they do not get autoboxed.
A primitive type is never "cast" to an object.
A primitive may be "autoboxed" into an object, but you can never determine this in code, since autoboxing is just code that is added by the compiler and is indistinguishable from the same code that you might have added by hand.
The output of the following program is 1,3,3 can someone explain it how?
will it consider 10.25 as a object to the method argument?
public class Test {
void methodOfTest(int i) {
System.out.println(1);
}
void methodOfTest(Integer I) {
System.out.println(2);
}
void methodOfTest(Object o) {
System.out.println(3);
}
public static void main(String[] args) {
Test t = new Test();
t.methodOfTest(10);
t.methodOfTest(10.25);
t.methodOfTest(new Double("25.25"));
}
}
t.methodOfTest(10);
10 is interpreted as int literal, so methodOfTest(int i) is called
t.methodOfTest(10.25);
There is no method, that takes a double, so the only method where 10.25 fits in is methodOfTest(Object o)
t.methodOfTest(new Double("25.25"));
Here we have a Double object, but again, no method is found that takes a Double, so the only method that takes this is again methodOfTest(Object o).
Therefore your output is 1,3,3.
It does not consider 10.25 to be an object. It does consider it to be assignment-convertible to an Object reference, by boxing conversion to a Double reference followed by widening reference conversion.
The boxing answers are absolutely correct.
I just wanted to add this: you were perhaps expecting an automatic (implicit) conversion from Double to Integer, but such a conversion must be declared explicitly (casting Double to Integer).
Without an explicit conversion, your Double value is interpreted as an Object (since you provided that method overload), which is the base class of about everything.
Hope this helps ;)
Because 10.25 can be converted to a Double. (boxing into Double)
So the constructor of Double will be called with 10.25 as parameter and will be passed to the method : void methodOfTest(Object o).
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.