How to cast an Object to Double?

W

www

Hi,

I cannot figure out how to do it well. I have an Object, which is
retrieved from a map. It actually is a number(double). I need to get its
value.

double value = Double.parse((String)theObj); //this works

But:

double value = (Double)theObj; //this does not work in Eclipse, why?

Is that because Double is subclass of Object, similarly a Animal can not
be casted into a Cat?

So, I have to cast the Object to String first, then get the double
value? (String is a subclass of Object(?). Why the Object can be casted
into String?)

Thank you.
 
L

Lew

www said:
I cannot figure out how to do it well. I have an Object, which is
retrieved from a map. It actually is a number(double). I need to get its
value.

double value = Double.parse((String)theObj); //this works

But:

double value = (Double)theObj; //this does not work in Eclipse, why?

It's not Eclipse that decides if this works, it's Java.
Is that because Double is subclass of Object, similarly a Animal can not
be casted into a Cat?
No.

So, I have to cast the Object to String first, then get the double
value? (String is a subclass of Object(?).
No.

Why the Object can be casted [sic] into String?)

Because all Objects have a toString() method. Beware, it might not do what
you expect.

This would be easier if you provided an SSCCE
<http://www.physci.org/codes/sscce.html>
but I'll do my best without one.

Assume a Map declared as

Map <String, Double> stuff = new HashMap <String, Double> ();

Later some code does:

Double d = stuff.get( key );

where key is some String. No casting needed.

If for some reason you were to use

Object o = stuff.get( key );

then you need to cast the return value, but that should work since you know
the map values are Double.

The only way I can imagine you getting the result you state, absent an SSCCE,
is that you used a raw Map type and inserted a non-Double into the value.

Provide an SSCCE and we'll see how close my guesses came.
 
R

RedGrittyBrick

www said:
Hi,

I cannot figure out how to do it well. I have an Object,

I try to avoid using Objects unless the API forces me.

which is retrieved from a map.

What sort of map? Some implementation of java.util.Map?

If it's something like HashMap then the problem could be made to go away
by using generics.

Map m = new HashMap<String, Double>();
m.put("hatsize", new Double(23.45));
...
double value = m.get("hatsize");

Note that Java will "autobox" Double and double.
I usually use a static constant or enum value in place of Strings like
"hatsize", but I'm digressing.
It actually is a number(double). I need to get its
value.

double value = Double.parse((String)theObj); //this works

But:

double value = (Double)theObj; //this does not work in Eclipse, why?

Is that because Double is subclass of Object, similarly a Animal can not
be casted into a Cat?

So, I have to cast the Object to String first, then get the double
value? (String is a subclass of Object(?). Why the Object can be casted
into String?)

I try to avoid explicit casting. Making more use of generics is one way
I do this.
 
L

Lew

RedGrittyBrick said:
If it's something like HashMap then the problem could be made to go away
by using generics.
Map m = new HashMap<String, Double>();

nitpicking:
Map<String, Double> m = new HashMap<String, Double>();
 
W

www

OK. My full testing program is:

public class HelloWorld
{

public static void main( String[] args )
{
Map<String, Object> map = new HashMap<String, Object>(10);

Properties states = new Properties();
try
{
states.load(new FileInputStream("property_file.txt"));
}
catch(IOException e) {

}

//copy entries from states file to the map
for (Map.Entry value : states.entrySet())
{
map.put((String)value.getKey(), value.getValue());
}


Object obj = map.get("HAT_SIZE");

double value = (Double)obj; //causing error!!!!!!!! I don't
understand why.

//following is ok, but why need to cast to String first?
double value = Double.parse((String)obj);


}

}

The property file("property_file.txt") has the content:
HAT_SIZE=5.999
SHOE_SIZE=3.23

Thank you for your help.
 
M

mrnohr

double value = (Double)obj; //causing error!!!!!!!! I don't understand why.
Try this:
double value = ((Double)obj).doubleValue();

Double (with a capital D) is a wrapper class and double (lower case d)
is a primitive datatype. This casts the object as a Double then gets
the primitive datatype from that.
 
W

www

mrnohr said:
Try this:
double value = ((Double)obj).doubleValue();

Double (with a capital D) is a wrapper class and double (lower case d)
is a primitive datatype. This casts the object as a Double then gets
the primitive datatype from that.

I have just tried it. It does not work.

Actually, I believe the following two are the same thing.

double value = (Double)obj;
double value = ((Double)obj).doubleValue();

The first one will automatically convert a Double object to a double
value and assign it to variable value.
 
M

Mark Rafn

OK. My full testing program is:

public class HelloWorld
{

public static void main( String[] args )
{
Map<String, Object> map = new HashMap<String, Object>(10);

Properties states = new Properties();
try
{
states.load(new FileInputStream("property_file.txt"));
}
catch(IOException e) {

}

//copy entries from states file to the map
for (Map.Entry value : states.entrySet())
{
map.put((String)value.getKey(), value.getValue());
}


Object obj = map.get("HAT_SIZE");

double value = (Double)obj; //causing error!!!!!!!! I don't
understand why.

//following is ok, but why need to cast to String first?
double value = Double.parse((String)obj);


}

}

The property file("property_file.txt") has the content:
HAT_SIZE=5.999
SHOE_SIZE=3.23

Good. One improvement would be for your test to actually compile (i.e.
include necessary imports, and leave the duplicate working line commented out.
More importantly, if you're getting an error, TELL US what it is! When I read
your post, I thought you were getting a compile error, and I couldn't see
why - you're allowed to cast an Object to a Double.

It turns out you're NOT getting a compile error, you're getting a runtime
error, and it is
Exception in thread "main" java.lang.ClassCastException: java.lang.String
at Foo.main(Foo.java:28)
This means you're trying to cast a String into a Double. That won't work.

Casting is different than parsing. Casting is just a way to tell one part of
the code that you, the developer, have more information about the type of the
object, and you want to try to use the object as if it were this more specific
type. If it's NOT actually usable as that type, it'll get a
ClassCastException.

A String isn't a Double. It's a String. So the cast fails.

What you want is to parse the string, meaning to read it's characters and see
what double it represents. You can do that by using the
Double.parseDouble(String) method. It takes a string, so if you know the
object is a String, you can cast it. That's your
double value = Double.parseDouble((String)obj);
line (note that it's parseDouble(), not parse()).

If you don't know that, you can call toString() on it.
double value = Double.parseDouble(obj.toString());

If you want a Double object rather than a double primitive value, you can use
Double value = new Double((String)obj);

Of course, many Strings, and even more non-String objects, have string values
that can't be parsed, and you'll get a NumberFormatException.
 
W

www

Mark Rafn wrote:
you're getting a runtime
error, and it is
Exception in thread "main" java.lang.ClassCastException: java.lang.String
at Foo.main(Foo.java:28)
This means you're trying to cast a String into a Double. That won't work.

Casting is different than parsing. Casting is just a way to tell one part of
the code that you, the developer, have more information about the type of the
object, and you want to try to use the object as if it were this more specific
type. If it's NOT actually usable as that type, it'll get a
ClassCastException.

A String isn't a Double. It's a String. So the cast fails.
Thank you so much for your reply. I still don't understand:

<java>
//copy entries from states file to the map
for (Map.Entry value : states.entrySet())
{
map.put((String)value.getKey(), value.getValue()); //I
thought it is String-Object pair!!!
}
<java>

Then, you are saying:

map.get("HAT_SIZE") is a String, that is why (Double)map.get("HAT_SIZE")
will fail. (A String cannot be casted to a Double).

I thought map.get("HAT_SIZE") is an Object, due to the map Generics
definition. If so, (Double)map.get("HAT_SIZE") should work.

I think:

map.put((String)value.getKey(), value.getValue());

is the one causing all the trouble and confusion. The values in the map
are a bunch of String, not Object. But why they are not Object?
value.getValue() is Object.

The map definition(Map<String, Object> map = new HashMap<String,
Object>(10)) also show that the value is Object type.
 
C

Christian

www said:
Mark Rafn wrote:
you're getting a runtime
Thank you so much for your reply. I still don't understand:

<java>
//copy entries from states file to the map
for (Map.Entry value : states.entrySet())
{
map.put((String)value.getKey(), value.getValue()); //I
thought it is String-Object pair!!!
}
<java>

Then, you are saying:

map.get("HAT_SIZE") is a String, that is why (Double)map.get("HAT_SIZE")
will fail. (A String cannot be casted to a Double).

I thought map.get("HAT_SIZE") is an Object, due to the map Generics
definition. If so, (Double)map.get("HAT_SIZE") should work.

I think:

map.put((String)value.getKey(), value.getValue());

is the one causing all the trouble and confusion. The values in the map
are a bunch of String, not Object. But why they are not Object?
value.getValue() is Object.

The map definition(Map<String, Object> map = new HashMap<String,
Object>(10)) also show that the value is Object type.

the problem ist not that they are not Object the problem is that they
are not Double..

you may only cast to Double what is of instance Double (means is Double
or extends double)

you can cast an animal to cat if it is a cat but you can't cast an
animal to dog if it is a cat, although it is also an animal..
 
M

Mark Rafn

www said:
<java>
//copy entries from states file to the map
for (Map.Entry value : states.entrySet())
{
map.put((String)value.getKey(), value.getValue()); //I
thought it is String-Object pair!!!
}
<java>

Map by itself is Object-Object. You specified <String, Object>, so the
compiler will enforce that for you as a convenience.

"HAT_SIZE" is a String, and is a fine key. "5.999" is a String as well. Since
a String is an Object, that's an allowable value in your map.
map.get("HAT_SIZE") is a String, that is why (Double)map.get("HAT_SIZE")
will fail. (A String cannot be casted to a Double).

You're using the String "HAT_SIZE" as a key. You're getting an Object "5.999"
which you, as a developer, know is a String, but the compiler doesn't. So you
have to cast it when you want to do something that requires it to be a String
rather than the more generic Object.

You can cast the Object "5.999" to a String, because it is. You can tell the
VM to cast it to a Double, but it'll fail when it tries, because it's not a
Double.
I thought map.get("HAT_SIZE") is an Object, due to the map Generics
definition. If so, (Double)map.get("HAT_SIZE") should work.

Do you think
Double d = (Double)"5.999";
would work? I don't. "5.999" is a string, not a number. You have to parse
it to get it's numeric value.

Note: if you'd declared your map to be <String, Double>, you'd have caught
this mistake earler, as the map.put() line would not have compiled. The
compiler would know you're trying to put a String into a Double value.
 
R

RedGrittyBrick

www said:
OK. My full testing program is:

public class HelloWorld
{

public static void main( String[] args )
{
Map<String, Object> map = new HashMap<String, Object>(10);

Properties states = new Properties();
try
{
states.load(new FileInputStream("property_file.txt"));

This loads the values as type String.
}
catch(IOException e) {

}

//copy entries from states file to the map
for (Map.Entry value : states.entrySet())
{
map.put((String)value.getKey(), value.getValue());
}

I'm not sure why you are copying a HashTable backed Properties object
into a new HashMap. Surely you could just use "states" where you later
use "map"?
Object obj = map.get("HAT_SIZE");

double value = (Double)obj; //causing error!!!!!!!! I don't
understand why.

Because obj is a String, you can't cast a String to a Double.

//following is ok, but why need to cast to String first?
double value = Double.parse((String)obj);

Because the compiler doesn't know the type of obj, you told the compiler
that obj was an Object, it doesn't know that obj will hold a String at
run-time.
}

}

The property file("property_file.txt") has the content:
HAT_SIZE=5.999
SHOE_SIZE=3.23

Note that 5.999 is a String even if it doesn't look like it.
Thank you for your help.

I'd rethink the approach to avoid all mention of type "Object".

e.g. one step along that path ...

public class PropertyDouble {
public static void main(String[] args) throws FileNotFoundException,
IOException {

Properties states = new Properties();
states.load(new FileInputStream("property_file.txt"));

// copy entries from states file to the map
Map<String, Double> map = new HashMap<String, Double>(10);
for (Map.Entry entry : states.entrySet()) {
String key = (String) entry.getKey();
Double value = Double.parseDouble(
(String) entry.getValue());
map.put(key, value);
}

double value = map.get("HAT_SIZE");

System.out.println("Double : " + Double.toString(value));
}
}
 
M

Mark Space

www said:
I thought map.get("HAT_SIZE") is an Object, due to the map Generics
definition. If so, (Double)map.get("HAT_SIZE") should work.

No. Java objects retain their type, always. They are never coverted to
anything else my casting. They always retain their type. The Double
object has a big old stamp on it that says "This is a Double." When you
cast, Java just looks at that stamp and says "Is it a Double?" If the
stamp says "String" instead, you get an error.

Object just tells the compiler what types to check. The cast has to be
supplied to the right type of object.

Even though the map says "Object" their types never change. It just
means the map will accept anything.
 
R

RedGrittyBrick

Maybe this makes it clearer ...

public class PropertyDouble {
public static void main(String[] args) throws FileNotFoundException,
IOException {

Properties states = new Properties();
states.load(new FileInputStream("property_file.txt"));

// copy entries from states file to the map
Map<String, Double> map = new HashMap<String, Double>(10);
for (Map.Entry entry : states.entrySet()) {

Object keyObj = entry.getKey();
if (keyObj instanceof String) {
System.out.println("Key is a String");
}
String key = (String) keyObj;

Object valueObj = entry.getValue();
if (valueObj instanceof String) {
System.out.println("Value is a String");
}
String valueString = (String) valueObj;
Double value = Double.parseDouble(valueString);

map.put(key, value);
}

double value = 2.54 * map.get("HAT_SIZE");
System.out.printf("Metric : %.4f \n", value);
}
}
 
L

Lew

RedGrittyBrick said:
Maybe this makes it clearer ...

public class PropertyDouble {
public static void main(String[] args)
throws FileNotFoundException, IOException {

Properties states = new Properties();
states.load(new FileInputStream("property_file.txt"));

One would be safer using a FileReader.
// copy entries from states file to the map

Since you already pointed out:
we could skip that copy. (It's actually a mistake Sun made having Properties
extend Hashtable.) I know you show it in order to make the points about
conversion, but let's take a look at what life is like without the copy:

Continuing the code snippet:
 
P

Patricia Shanahan

www wrote:
....
The map definition(Map<String, Object> map = new HashMap<String,
Object>(10)) also show that the value is Object type.

There are two issues that are combined here, and are better kept separate:

1. The class of an object. The class of each object is specified when it
is created, either new or by cloning an existing object. It cannot be
changed during the object's life.

2. The type of a variable or expression. The type of a variable or
expression can be calculated at compile time.

A reference expression can point to some object if, and only if, the
type of the expression corresponds to the object's class, or to one of
its superclasses, or one of the interfaces it implements.

During an object's life, it may be referenced by expressions of any
appropriate type. Similarly, an expression may reference objects of
different classes at different times.

Object is the ultimate superclass, so an Object expression, such as the
result of get on a Map<String,Object> can reference ANY object,
regardless of its class. In this case, it happens to point to a String.

That String remains a String, regardless of whether the type of the
referencing expression is Object, String, Serializable, CharSequence, or
Comparable<String>.

Patricia
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top