• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Boxing and widening

 
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,
I have been searching for an answer, but not really found what I was looking for.

Given this:

public class WideBox {
private static void test(Long l) { System.out.println("Long: " + l); }
private static void test(float f) { System.out.println("float: " + f); }
private static void test(Object o) { System.out.println("Object: " + o); }
public static void main(String[] args) {
int i = 10;
long l = 20;
Integer io = 30;
Float f = 40.0f;
double d = 50.0;

test(i);
test(l);
test(io);
test(f);
test(d);

l = 0x7ffffffffL;
test(l);
}
}

/*
> "java" WideBox
float: 10.0
float: 20.0
Object: 30
Object: 40.0
Object: 50.0
float: 3.4359738E10

*/

I assume that the long doesn't get boxed to Long but instead narrowed to a float in order not to break compatibility with previous Java versions. But why is there no warning when I compile (or at runtime) that I will loose precision?

The Float gets widened to an Object, as far as I understand for the same reason - not to break compatibility.

The double, however, is boxed into an Object (via Double). How come?

Best Regards,
Anders Nystedt
 
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

But why is there no warning when I compile (or at runtime) that I will loose precision?



Widening is based on range, not precision. As long as the range of the target type can cover the range of the source type, it will implicitedly cast.

The double, however, is boxed into an Object (via Double). How come?



What are the other options? It can't be narrowed to a float implicitedly.

Henry
 
Sheriff
Posts: 11343
Mac Safari Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Anders Nystedt:
... I assume that the long doesn't get boxed to Long but instead narrowed to a float in order not to break compatibility with previous Java versions. But why is there no warning when I compile (or at runtime) that I will loose precision?

The Float gets widened to an Object, as far as I understand for the same reason - not to break compatibility.

The double, however, is boxed into an Object (via Double). How come? ...


Welcome to JavaRanch!

I think the confusion centers around conversions from integral to floating-point primitives. According to JLS - 5.1.2 Widening Primitive Conversion a long to float or double is, in fact, a widening conversion.

Widening primitive conversions do not lose information about the overall magnitude of a numeric value...

Conversion of an int or a long value to float, or of a long value to double, may result in loss of precision -- that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode (�4.2.4).


So the order of widening is byte > short > int > long > float > double. (A char can be widened to type int or wider, but a byte or short cannot be widened to type char.) For widening conversions, it's up to the programmer to recognize a possible loss of precision.

Then according to JLS - 5.3 Method Invocation Conversion...

Method invocation contexts allow the use of one of the following:

  • an identity conversion (�5.1.1)
  • a widening primitive conversion (�5.1.2)
  • a widening reference conversion (�5.1.5)
  • a boxing conversion (�5.1.7) optionally followed by widening reference conversion
  • an unboxing conversion (�5.1.8) optionally followed by a widening primitive conversion.
  • So in your example, the long is widened to float. A double cannot be widened any further, so it is boxed to Double, and that reference is widened to Object.
     
    Anders Nystedt
    Greenhorn
    Posts: 4
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thank you very much - this is a great site!

    I was looking on the bit size of the types and could not understand that a 64 bit long could fit into a 32 bit float - now I've learned that this was actually a widening ;-)

    Then I thought that, "well, if a 64 bit long could fit into a float, why could not a double do the same", kind of stupid, but it's getting late...

    But now it's very clear what is going on, many thanks for that!

    Anders
    reply
      Bookmark Topic Watch Topic
    • New Topic