Java Forum / General / September 2006
Annoying 1.5 warnings
aaronfude@gmail.com - 01 Sep 2006 14:54 GMT Why does the following code cause a warning and how to avoid it w/o turning warnings off?
Vector<File> a = (Vector<File>) (Object) new Vector<File>();
The warning is:
Type safety: The cast from Object to Vector<File> is actually checking against the erased type Vector
Robert Klemme - 01 Sep 2006 15:00 GMT > Why does the following code cause a warning Because you cast from Object to Vector<File>.
> and how to avoid it w/o > turning warnings off? Don't do unnecessary casts up and down the class hierarchy.
> Vector<File> a = (Vector<File>) (Object) new Vector<File>(); > > The warning is: > > Type safety: The cast from Object to Vector<File> is actually checking > against the erased type Vector Right it is.
Regards
robert
Zaph0d - 01 Sep 2006 16:05 GMT > > and how to avoid it w/o > > turning warnings off? > > Don't do unnecessary casts up and down the class hierarchy. Wrong.
> > Vector<File> a = (Vector<File>) (Object) new Vector<File>(); To understand the warning, you need to understand how generics work. While at compile time generic types are full, meaning Vector<String> is not Vector<Integer>, at runtime this distinction goes away, meaning Vector<String> is Vector<Integer>. The process is called erasure and it is done to remain backward compatible with Java 1.4 jvm (Code with generics but no other 1.5 features, compiled with jdk 1.5, will run on jvm 1.4).
How does this affect you? At compile time you enjoy the generic type safety telling you that "new Vector<Integer>().add("hi!");" will not work. But (and there's always a "but"), at runtime there is no way to distinguish between Vector<String> and Vector<Integer>. That means that the compiler can't tell you you're doing a mistake. So: "Vector<String> vs = ((Vector<String>) ((Object) new Vector<Integer>));" would work. However, the next sequence would result in a casting exceptions: "vs.add(123); String s = vs.elementAt(0);", although generic wise it's "supposed" to be safe (since vs is Vector<String>). To tell you this, the compiler emits the warning you saw.
Robert Klemme - 01 Sep 2006 16:07 GMT >> > and how to avoid it w/o >>> turning warnings off? >> Don't do unnecessary casts up and down the class hierarchy. > > Wrong. Why is that wrong? Is not Object the super class of Vector and also Vector<File> for that matter?
robert
aaronfude@gmail.com - 01 Sep 2006 16:40 GMT OK, my example was just the simplest thing I could think of. My real problem is that I need to store Vector<String> in a collection with other Objects. As a result, when I retrieve on Object via a get() I need to cast it to a Vector<String> and the cast causes the warning. So my casts are not unnecessary.
Zaph0d - 01 Sep 2006 19:12 GMT robert:
> Why is that wrong? Is not Object the super class of Vector and also > Vector<File> for that matter? This is wrong because the original warning did not refer to that problem.
> OK, my example was just the simplest thing I could think of. My real > problem is that I need to store Vector<String> in a collection with > other Objects. As a result, when I retrieve on Object via a get() I > need to cast it to a Vector<String> and the cast causes the warning. So > my casts are not unnecessary. Your cast are necessary, but you shouldn't cast to Vector<String> but to Vector. If you cast to Vector<String> and it's not (if it's Vector<Integer> for example), you'll get weird runtime errors in unpredictable places. Also, please be aware that you can't test for Vector<String> but just for Vector (erasure again). Makes life a little more complicated.
aaronfude@gmail.com - 01 Sep 2006 20:02 GMT You mean, Vector<String> v = (Vector) (Object) new Vector<String>(); ?
Well, that causes another warning:
Type safety: The expression of type Vector needs unchecked conversion to conform to Vector<String>
Zaph0d - 02 Sep 2006 13:18 GMT > You mean, > Vector<String> v = (Vector) (Object) new Vector<String>(); [quoted text clipped - 5 lines] > to conform to > Vector<String> Of course, becuase v is Vector<String> while the right-hand side is typecasted to Vector. This means that you expect v.get(...) to return String, but it might throw a typecast exception (becuase the original isn't a String).
Robert Klemme - 02 Sep 2006 21:49 GMT > robert: >> Why is that wrong? Is not Object the super class of Vector and also >> Vector<File> for that matter? > > This is wrong because the original warning did not refer to that > problem. Ah, I see. Thanks for the heads up!
robert
aaronfude@gmail.com - 03 Sep 2006 12:48 GMT So, to sum up, no way to get rid of the warning?
Zaph0d - 03 Sep 2006 18:14 GMT > So, to sum up, no way to get rid of the warning? huh? how did you come up with that?
Just do Vector<YourType> vec = new Vector<YourType>();
aaronfude@gmail.com - 03 Sep 2006 22:07 GMT Happy to explain again. (Pseudo code...)
TreeMap<Object, Object> miscStuff = new TreeMap<Object, Object>();
miscStuff.put("A Vector of Ints", new Vector<Integer>()); miscStuff.put("A Vector of Strings", new Vector<String>());
Now:
Vector<Integer> v = (Vector<Integer>) miscStuff.get("A Vector of Ints"); gives a warning
Vector<Integer> v = (Vector) miscStuff.get("A Vector of Ints"); gives a warning
Vector<Integer> v = miscStuff.get("A Vector of Ints"); gives an error
What is your suggestion?
Thank you
John W. Kennedy - 04 Sep 2006 02:29 GMT > Happy to explain again. (Pseudo code...) > [quoted text clipped - 16 lines] > > What is your suggestion? Redesign miscStuff so as not to be filled with different things.
Failing that, use the first option, and accept the warning.
 Signature John W. Kennedy "The blind rulers of Logres Nourished the land on a fallacy of rational virtue." -- Charles Williams. "Taliessin through Logres: Prelude"
Zaph0d - 04 Sep 2006 07:39 GMT > Failing that, use the first option, and accept the warning. Failgin that, use Vector<Object> to bypass the warning (though gain no real type-safety).
Hendrik Maryns - 04 Sep 2006 09:53 GMT Zaph0d schreef:
>> Failing that, use the first option, and accept the warning. > Failgin that, use Vector<Object> to bypass the warning (though gain no > real type-safety). Failing that, use @SuppressWarnings("unchecked")
H. - -- Hendrik Maryns
================== http://aouw.org Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
ricky.clarkson@gmail.com - 04 Sep 2006 11:08 GMT Aaron,
A TreeMap<Object,Object> is intrinsically not a usefully typed collection; you have just added it to make the compiler shut up, or because you think you should for generics.
In your case, it appears that you are using Strings as keys, and either a Vector<Integer> or a Vector<String> as a value.
The problem with this is that at runtime, Vector<Integer> is just a Vector, and Vector<String> is just a Vector; there is no way for the compiler or the runtime to ensure that you are operating on what you think you are. Throw an invisible ball to your friend; you cannot know whether he caught it.
Polymorphism is a useful tool for dealing with this. As you are using Vector, your Java book probably predates modern code, so I'll demonstrate this with abstract classes rather than interfaces.
This solution makes a homogenous (same-type) collection out of what was a heterogenous (lots of different types) collection. Another solution might be to make more than one collection instead, one for each type. Anyway, here goes the visitor design pattern:
abstract class VectorHolder { public abstract void accept(VectorVisitor visitor); }
abstract class VectorVisitor { public abstract void visitStringVector(Vector<String> vector); public abstract void visitIntegerVector(Vector<Integer> vector); }
class StringVectorHolder extends VectorHolder { private final Vector<String> vector;
public StringVectorHolder(Vector<String> vector) { this.vector=vector; }
public void accept(VectorVisitor visitor) { visitor.visitStringVector(vector); } }
class IntegerVectorHolder extends VectorHolder { private final Vector<Integer> vector;
public IntegerVectorHolder(Vector<Integer> vector) { this.vector=vector; }
public void accept(VectorVisitor visitor) { visitor.visitIntegerVector(vector); } }
Now your map is:
TreeMap<String,VectorHolder>
If you have more types than just these two, you can add a method in VectorVisitor, e.g., visitColor, and then make a ColorVectorHolder. Of course, VectorHolder and VectorVisitor might be bad names if you use anything other than Vectors there..
Don't dismiss this immediately as being a lot of useless code; it is giving you real runtime information about the elements in your collection, without you having to cast.
Casting is for magicians.
> Happy to explain again. (Pseudo code...) > [quoted text clipped - 18 lines] > > Thank you ricky.clarkson@gmail.com - 04 Sep 2006 11:16 GMT And now the same thing in my preferred coding style:
interface Holder { void accept(Visitor visitor); }
interface Visitor { void visitStringList(List<String> list); void visitIntegerList(List<Integer> list); }
class Holders { public static Holder stringList(final List<String> list) { return new Holder() { public void accept(Visitor visitor) { visitor.visitStringList(list); } }; }
public static Holder integerList(final List<Integer> list) { return new Holder() { public void accept(Visitor visitor) { visitor.visitIntegerList(list); } }; } }
TreeMap<String,Holder> map=new TreeMap<String,Holder>();
map.put("a list of ints",Holders.integerList(new ArrayList<Integer>()));
map.put("a list of strings",Holders.stringList(new ArrayList<String>()));
No type safety lost, and generics as erasure is causing no problems, as usual.
> Aaron, > [quoted text clipped - 99 lines] > > > > Thank you Greg R. Broderick - 04 Sep 2006 18:38 GMT aaronfude@gmail.com wrote in news:1157284132.474909.299540 @m79g2000cwm.googlegroups.com:
> So, to sum up, no way to get rid of the warning? Not if you want to continue storing the Vector of Strings in a collection with other Objects -- your design is intentionally defeating Java's type safety rules.
Cheers! GRB
 Signature --------------------------------------------------------------------- Greg R. Broderick gregb.usenet200607@blackholio.dyndns.org
A. Top posters. Q. What is the most annoying thing on Usenet? ---------------------------------------------------------------------
aaronfude@gmail.com - 07 Sep 2006 15:57 GMT > aaronfude@gmail.com wrote in news:1157284132.474909.299540 > @m79g2000cwm.googlegroups.com: [quoted text clipped - 7 lines] > Cheers! > GRB Point well taken, but how do I clone() a Vector<Integer> without a warning?
Hendrik Maryns - 07 Sep 2006 16:25 GMT aaronfude@gmail.com schreef:
>> aaronfude@gmail.com wrote in news:1157284132.474909.299540 >> @m79g2000cwm.googlegroups.com: [quoted text clipped - 9 lines] > Point well taken, but how do I clone() a Vector<Integer> without a > warning? new Vector<Integer>(oldVector);
Are you sure you do not want an ArrayList?
H. - -- Hendrik Maryns http://tcl.sfs.uni-tuebingen.de/~hendrik/ ================== http://aouw.org Ask smart questions, get good answers: http://www.catb.org/~esr/faqs/smart-questions.html
ricky.clarkson@gmail.com - 10 Sep 2006 17:25 GMT Clone is a broken API in the context of Java 1.5, because it actually mentions Object.
Object was only necessary without generics, now we can use type parameters.
Angelika Langer has something to say on the matter: http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#How %20do%20I%20best%20implement%20the%20clone%20method%20of%20a%20parameterized%20t ype
Cloning is very often not what you want anyway, as it is shallow copying.
Serialising and deserialising tends to be more thorough, but very wasteful. I'd rather avoid 'magic' behaviour, and write an explicit copy constructor or factory method, which is the approach the Java collections APIs take.
Cheers.
> > aaronfude@gmail.com wrote in news:1157284132.474909.299540 > > @m79g2000cwm.googlegroups.com: [quoted text clipped - 10 lines] > Point well taken, but how do I clone() a Vector<Integer> without a > warning? M.J. Dance - 01 Sep 2006 15:01 GMT > Why does the following code cause a warning and how to avoid it w/o > turning warnings off? > > Vector<File> a = (Vector<File>) (Object) new Vector<File>(); Vector<File> a = new Vector<File>();
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|