Reputation: 59355
The following method generates a warning, but it looks safe to me. I'm sure the problem is with me:
public <S extends CharSequence> S foo(S s) {
return (S) new StringBuilder(s);
}
It looks like this will always return the argument s
. Can anyone show an example that would cause this method to throw an exception?
Edit: I'm not particularly interested in the question of whether generics are necessary here. Rather, I'm looking for a demonstration of how this method is unsafe.
Upvotes: 2
Views: 668
Reputation:
The return type of your method code is ALWAYS a StringBuilder.
That is because the declared type of the expression 'new StringBuilder(x)' is ALWAYS a StringBuilder, whatever the X.
It is TOTALLY pointless to try and cast this to anything. The "S" information is part of the erasure, which exists only at compile-time and is erased by the time the program runs, that is, run-time. (Casting is a run-time thing exclusively, and casting something to some type/class whose identity has been erased a run-time, is indeed totally pointless.)
Upvotes: 1
Reputation: 31053
The unsafety here lies not within the method itself (though it has its problems, too) but at the call site. The use of S for the input argument's type as well as for the return value tells the compiler, that whatever the type of object may be that is passed to the function, the result has the same type (or a derived type, actually).
Thus, the compiler is allowed to assume, that in the call
foo("hello, world")
the result will be a java.lang.String, while in the call
foo(new StringBuffer("hello, world"))
the result will be a StringBuffer, and so on. In both cases, however, your method does not return what it was supposed to return, namely, an object of the same type as the input argument. Instead, a StringBuilder is returned.
Actually, the only kind of input argument your method will work with is a StringBuilder, anything else will be doomed to crash with a ClassCastException sooner or later, as the compiler might (and often does) insert (hidden) casts at the call sites.
And of course, as others have already pointed out, the use of generics is not really necessary here, anyway.
Upvotes: 1
Reputation: 116334
For example this will compile:
String a = foo("ss");
but it will fail at runtime:
ClassCastException: java.lang.StringBuilder cannot be cast to java.lang.String
since foo
returns S
, the type of your input parameter (String
in this case).
I think that you don't need to use generics here (as skaffman said in his answer):
public StringBuilder foo(CharSequence s) {
return new StringBuilder(s);
}
Upvotes: 2
Reputation: 403471
It's unsafe because while StringBuilder is a CharSequence, it isn't necessarily of type S (in fact, it almost certainly won't be). You can see this failing just by passing a String
into your method. This will construct a StringBuilder
using your String
as an argument, and then try to cast your StringBuilder
to String
(which will fail).
There's probably no need to use generics here at all, this should work fine:
public CharSequence foo(CharSequence s) {
return new StringBuilder(s);
}
Upvotes: 6
Reputation: 5122
foo("test");
is enough to make java try to cast a StringBuilder in a String.
Your code is guaranteed o be wrong, can you explain what you're trying to achieve plase ?
Upvotes: 1
Reputation: 61233
my Java is rusty, but would this method not throw whatever exceptions
new StringBuilder(s)
can throw?
Upvotes: 0