Let's say that I have a class:
class A {
private Integer i;
public int getI() {
return i;
}
// Setter, etc.
}
and I write:
A a = // initializer
Integer b = a.getI();
how many Integers will there be? My naive reading about autoboxing/unboxing leads me to believe that the answer is 2, but if getI() were:
public Integer getI();
then the answer would be 1.
You are absolutely correct, with one caveat: the answer to the first part depends on the value of Integer i.
In the first scenario, one Integer is created in the constructor, and the other one is created when boxing the int coming from getI()
In the second scenario, there needs to be no boxing, so there's only one Integer object.
Note: if the value of the Integer i is small (more precisely, between -128 and 127, inclusive), autoboxing will produce the same Integer through interning.
Correct....ish
It's theoretically possible the Compiler/JIT/JVM/etc could optimise out the autoboxing but I've no idea if it actually would.
It's also possible the same Integer object would be re-used. For example Integer.valueOf(2) is guaranteed to give you the same Integer object every time you call it and re-use the same object. This is only guaranteed for values in the range -128 to +127 inclusive though, it may happen outside that range but should not be relied upon.
Related
Can an int be null in Java?
For example:
int data = check(Node root);
if ( data == null ) {
// do something
} else {
// do something
}
My goal is to write a function which returns an int. Said int is stored in the height of a node, and if the node is not present, it will be null, and I'll need to check that.
I am doing this for homework but this specific part is not part of the homework, it just helps me get through what I am doing.
Thanks for the comments, but it seems very few people have actually read what's under the code, I was asking how else I can accomplish this goal; it was easy to figure out that it doesn't work.
int can't be null, but Integer can. You need to be careful when unboxing null Integers since this can cause a lot of confusion and head scratching!
e.g. this:
int a = object.getA(); // getA returns a null Integer
will give you a NullPointerException, despite object not being null!
To follow up on your question, if you want to indicate the absence of a value, I would investigate java.util.Optional<Integer>
No. Only object references can be null, not primitives.
A great way to find out:
public static void main(String args[]) {
int i = null;
}
Try to compile.
In Java, int is a primitive type and it is not considered an object. Only objects can have a null value. So the answer to your question is no, it can't be null. But it's not that simple, because there are objects that represent most primitive types.
The class Integer represents an int value, but it can hold a null value. Depending on your check method, you could be returning an int or an Integer.
This behavior is different from some more purely object oriented languages like Ruby, where even "primitive" things like ints are considered objects.
Along with all above answer i would like to add this point too.
For primitive types,we have fixed memory size i.e for int we have 4 bytes and char we have 2 bytes. And null is used only for objects because there memory size is not fixed.
So by default we have,
int a=0;
and not
int a=null;
Same with other primitive types and hence null is only used for objects and not for primitive types.
The code won't even compile. Only an fullworthy Object can be null, like Integer. Here's a basic example to show when you can test for null:
Integer data = check(Node root);
if ( data == null ) {
// do something
} else {
// do something
}
On the other hand, if check() is declared to return int, it can never be null and the whole if-else block is then superfluous.
int data = check(Node root);
// do something
Autoboxing problems doesn't apply here as well when check() is declared to return int. If it had returned Integer, then you may risk NullPointerException when assigning it to an int instead of Integer. Assigning it as an Integer and using the if-else block would then indeed have been mandatory.
To learn more about autoboxing, check this Sun guide.
instead of declaring as int i declare it as Integer i then we can do i=null;
Integer i;
i=null;
Integer object would be best. If you must use primitives you can use a value that does not exist in your use case. Negative height does not exist for people, so
public int getHeight(String name){
if(map.containsKey(name)){
return map.get(name);
}else{
return -1;
}
}
No, but int[] can be.
int[] hayhay = null; //: allowed (int[] is reference type)
int hayno = null; //: error (int is primitive type)
//: Message: incompatible types:
//: <null> cannot be converted to int
As #Glen mentioned in a comment, you basically have two ways around this:
use an "out of bound" value. For instance, if "data" can never be negative in normal use, return a negative value to indicate it's invalid.
Use an Integer. Just make sure the "check" method returns an Integer, and you assign it to an Integer not an int. Because if an "int" gets involved along the way, the automatic boxing and unboxing can cause problems.
Check for null in your check() method and return an invalid value such as -1 or zero if null. Then the check would be for that value rather than passing the null along. This would be a normal thing to do in old time 'C'.
Any Primitive data type like int,boolean, or float etc can't store the null(lateral),since java has provided Wrapper class for storing the same like int to Integer,boolean to Boolean.
Eg: Integer i=null;
An int is not null, it may be 0 if not initialized. If you want an integer to be able to be null, you need to use Integer instead of int . primitives don't have null value. default have for an int is 0.
Data Type / Default Value (for fields)
int ------------------ 0
long ---------------- 0L
float ---------------- 0.0f
double ------------- 0.0d
char --------------- '\u0000'
String --------------- null
boolean ------------ false
Since you ask for another way to accomplish your goal, I suggest you use a wrapper class:
new Integer(null);
I'm no expert, but I do believe that the null equivalent for an int is 0.
For example, if you make an int[], each slot contains 0 as opposed to null, unless you set it to something else.
In some situations, this may be of use.
In the below class I have tried to compare the wrapper class with the primitive but the results are different.
I have checked the following links links:
The more interesting question is why new Object(); should be required to create a unique instance every time? i. e. why is new Object(); not allowed to cache? The answer is the wait(...) and notify(...) calls. Caching new Object()s would incorrectly cause threads to synchronize with each other when they shouldn't.
If there is a new object then how are a and c equal?
If b is equal to c and c is equal to a, then a should be equal to b. But in following case I got a != c.
Please explain.
class WrapperCompare {
public static void main (String args[]) {
Integer a = new Integer(10);
Integer b = 10;
int c=10;
System.out.println(b==c); //true
System.out.println(a==b); //false
System.out.println(a==c); //true
}
}
Update:
By referring to this link Integer caching.
Basically, the Integer class keeps a cache of Integer instances in the range of -128 to 127, and all autoboxing, literals and uses of Integer.valueOf() will return instances from that cache for the range it covers.
So in this case all statements should be true.
Explanation
When you compare Integer vs int with ==, it needs to convert the Integer to an int. This is called unboxing.
See JLS§5.1.8:
If r is a reference of type Integer, then unboxing conversion converts r into r.intValue()
At that point, you are comparing int vs int. And primitives have no notion of instances, they all refer to the same value. As such, the result is true.
So the actual code you have is
a.intValue() == c
leading to a comparison of 10 == 10, both int values, no Integer instances anymore.
You can see that new Integer(...) indeed creates new instances, when you compare Integer vs Integer. You did that in a == b.
Note
The constructor new Integer(...) is deprecated. You should instead use Integer#valueOf, it is potentially faster and also uses an internal cache. From the documentation:
Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
The caching is important to note here, since it yields to == being true again (for cached values):
Integer first = Integer.valueOf(10);
Integer second = Integer.valueOf(10);
System.out.println(first == second); // true
The caching is guaranteed for values between -128 and +127, but may also be used for others.
Also note that your b actually comes out of the cache, since
Integer b = 10;
// same as
Integer b = Integer.valueOf(10);
// and not
Integer b = new Integer(10);
So boxing goes through Integers cache (see JLS§5.1.7).
This is my code:
public class Test
{
public static void main(String arg[]) {
new Test().method1(5);
}
public void method1(int b) { // integer method
System.out.println("integer ");
}
public void method1(short a) { // short method
System.out.println("short");
}
}
I am running this class, and it gives me result of integer. Why it is not giving short?
Because the literal 5 is by default understood as an int. If you want to call the method1(short a) method, you need to explicitly do a cast:
new Test().method1((short) 5);
The literal 5 has type int, that's why the method that expects an int is called.
new Test().method1((short)5) would call the method that expects a short.
Default type of Java integer literals is int thats why integer method is getting invoked.
you have to apply type conversion because you are willing to call a function which receives short.
try calling with:(short)5
It's because, as noted in the other answers, a 5 on its own denotes an int. You can denote a long by appending an L, so 5L would be treated as a long. If you want a byte or a short then you have to cast explicitly.
It may be that you have a good reason for wanting a method that takes a short, but please bear in mind that this is quite rare. Certainly you would not want to be doing this for performance reasons. Java uses a 32-bit int by default because pretty much every processor out there can work natively with 32-bit integers. You will probably find that a short will operate more slowly than an int.
(Of course, if you're doing specifically 16-bit arithmetic, then you might still need to use a short.)
There's a general advice to use Integer.valueOf(int) instead of new Integer(int) because of caching.
In JDK 5+, you should really use valueOf because Integer now caches Integer objects between -128 and 127 and can hand you back the same exact Integer(0) object every time instead of wasting an object construction on a brand new identical Integer object.
How can extend the range?
You can use the java.lang.Integer.IntegerCache.high property to increase the size of this cache.
ex :
java -Djava.lang.Integer.IntegerCache.high=4096 SomeClass.class
My questions to you are:
1) Why is your code making new Integer objects hurting you? Do you have a profile result to share, to prove that making too many Integers is slowing your down? Object pooling, in general, is a BAD idea. You need a good case to justify it.
2) Why are you doing new Integer(int)? If you just keep it as a primitive int, not only will you avoid "creating a new object". you will not create any object at all. Auto boxing will handle converting it to an Integer if you need it at a later point in time.
*Disclaimer I Don't use EITHER.. I write performance sensitive code, but have never come to a point where I would manually turn a primitive int into an Integer. I just keep as an int whenever possible, and let the JVM autobox if it is needed.
Apparently, the -XX:+AggressiveOpts sets the max to 20000. See the answer on How large is the Integer cache?
Extending the range of the cache may not get you what you are wanting, but if you have a real need to cache a greater range, you can use this code instead of Integer.valueOf(int). You just need to adjust the cache range values to the range you want.
private static class IntegerCache
{
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static
{
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}
public static Integer valueOf(int i)
{
final int offset = 128;
if (i >= -128 && i <= 127) // must cache
{
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
The code is from: http://www.owasp.org/index.php/Java_gotchas
This is why the integer cache was added:
[...] to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive), as required by the language specification.
If you profiled your app and you noticed that creating Integer objects is a hotspot, then by all means, copy the integer cache code and write your own with a different range. Otherwise your time would be better spent finding the real hotspots and improving those.
Running this code:
public class SomeSet {
public static void main(String[] args) {
Set<Short> s = new HashSet<Short>();
for (short i = 0; i < 100; i++) {
s.add(i);
s.remove(i - 1);
}
System.out.println(s.size());
}
}
Will print the value 100.
Why does it print this value?
s.remove(i - 1);
The line above will attempt to remove Integer objects from the set, because all integer calculations in Java have int (or long) results. Since the set contains Short objects, the remove() method will not have any effect.
This (and similar problems) is the main reason why you should almost never use short (and, more so, Short). Using a Set implementation to contain autoboxed numbers incurs a massive (easily 1000%) overhead, so it's rather pointless to try and save space by using Short rather than Integer.
The problem is that remove(i-1) calls the remove method with an Integer object, since i-1 is of type int (which gets auto-boxed into an Integer).
To make sure that you call remove with a Short object use this:
s.remove((short) (i - 1));
The type of i - 1 is int, so it gets autoboxed to an Integer.
Normally you'd expect a generic collection to prevent you performing operations which have arguments of the wrong type, but the interface to Set<E> is a bit loose.
Because the remove method of Set<E> takes an Object rather than an E, the compiler doesn't warn you that you're removing a different type to what the set contains.
To force it to be a Short, cast the numeric value to (short). (casting to (Short) isn't allowed, and you'd have to cast the numeric value to use Short.valueOf)
Note that the add method is generically typed boolean add(E o) so in your case of Set the add method will take a short, whereas the remove method is not generically typed boolean remove(Object o) so i - 1 autoboxes to a Integer. For any value of i new Short(i).equals(new Integer(i)) will always be false.
Note that if you try s.add(i - 1); you will get a compiler error because i - 1 becomes an instance of Integer and the types Integer and Short do not match.