If I have this class:
class A {
public A(String a);
}
Is it possible to make an instance through reflection without getting a
compiler warning (java 1.5)?
The following gives an unchecked warning in the first line due to the
forced cast. Using "?" just postpone the the problem:
Class<A> clazz = (Class<A>) Class.forName("A");
Constructor<A> ctor = clazz.getConstructor(String.class);
A a = ctor.newInstance("hello world");
The problem is that in my organization we treat warnings as errors and
the above simply isn't doable within such a regime.
What is the workaround?
(And why whould all the above be possible (by Class<?> and Class.newInstance()),
if just the constructor didn't take any arguments?)
Thanks!
Tony Morris - 31 Jan 2006 00:31 GMT
> If I have this class:
>
[quoted text clipped - 21 lines]
>
> Thanks!
Hello Jacob,
I have seen this question quite a number of times, which prompted me to add
it to my FAQ.
http://jqa.tmorris.net/GetQAndA.action?qids=80&showAnswers=true
I have also included a code sample below that demonstrates what you want to
achieve.
As a note, if you have a policy of not being permitted to have compile-time
warnings, it may be in your interest to learn about generics.
Also note that there are some valid use cases that force a compile-time
warning, due to the contrived nature of the Java generics implementation, so
you may seek to have this policy reviewed. These forced use cases are the
result of the introduction of failure to maintain a conversion between
arrays and parameterised types (without a warning) - as an example, take a
look at the java.util.ArrayList implementation, which is backed by an
array - you will note that there is a forced compile-time warning. You
discover these nitty details when you implement the spec. after a JSR
"expert" group has been onto the case :) I did make this issue known well
before the spec. was released, but the most plausible response I got was
"oops".
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import static java.lang.Class.forName;
class X
{
X(final String s)
{
}
}
final class Main
{
private Main() throws UnsupportedOperationException
{
throw new UnsupportedOperationException();
}
public static void main(final String... args) throws
ClassNotFoundException,
NoSuchMethodException,
InstantiationException,
IllegalAccessException,
InvocationTargetException
{
final Class<?> c = forName("X");
final Class<? extends X> xc = c.asSubclass(X.class);
final Constructor<? extends X> ctor =
xc.getConstructor(String.class);
final X x = ctor.newInstance(args[0]);
}
}
--
Tony Morris
http://tmorris.net/
Java Questions and Answers
http://jqa.tmorris.net/
Chris Uppal - 31 Jan 2006 11:42 GMT
> The problem is that in my organization we treat warnings as errors and
> the above simply isn't doable within such a regime.
Ha ha! Then you loose!
I'm not sure about the particular example you mention -- I don't know a
(working) way to avoid the warning myself, but that doesn't mean there isn't
one[*].
But the real problem here is not javac, but the way your organisation works.
Find the person responsible for this absurd rule and fire him/her (and,
perhaps, also his/her manager). Or if the condition was imposed by a customer,
find the salesthing which accepted that clause in the contract and fire it.
-- chris
[*] Well, I suppose you could compile with -source 1.4
Roedy Green - 31 Jan 2006 13:43 GMT
>The following gives an unchecked warning in the first line due to the
>forced cast. Using "?" just postpone the the problem:
>
> Class<A> clazz = (Class<A>) Class.forName("A");
> Constructor<A> ctor = clazz.getConstructor(String.class);
> A a = ctor.newInstance("hello world");
Unchecked means the compiler cannot guarantee safety at compile time.
The truth is it can't. It has absolutely no idea what A will be/do. If
you want the compiler to be able to check, it wants to see the code at
compile time.
Further this code makes no sense to me. If type A is known at compile
time, why are you dicking around with Class.forName. You only do that
when you DON'T know the class name, just an interface it implements..

Signature
Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.
Ian Pilcher - 31 Jan 2006 15:12 GMT
> If I have this class:
>
[quoted text clipped - 14 lines]
> The problem is that in my organization we treat warnings as errors and
> the above simply isn't doable within such a regime.
In this case, you can use Class.asSubclass:
Class<A> clazz = Class.forName("A").asSubclass(A.class);
As Tony pointed out, there are perfectly valid (and sometimes
unavoidable) constructs which will produce unchecked cast warnings.
Read up on the @SuppressWarnings annotation, and note that Sun's
compiler didn't support it until 1.5.0_06.
I'm assuming that the code you posted is a contrived example. If not,
Roedy's comment is right on; there's no reason to use Class.forName for
a known type.
HTH

Signature
========================================================================
Ian Pilcher i.pilcher@comcast.net
========================================================================
Jacob - 01 Feb 2006 06:53 GMT
> If I have this class:
>
> class A {
> public A(String a);
> }
As pointed out, a better example should be
class A implements B {
public A(String a);
}
Class<A> clazz = (Class<A>) Class.forName("A");
Constructor<A> ctor = clazz.getConstructor(String.class);
B b = ctor.newInstance("hello world");
Though I may understand *why* the compiler complains, I
have a feeling that a warning from the compiler is a strong
hint to modify the code so that the warning disappears.
What use has a warning if it is always there? But I guess
it boils down to the definition of the term "warning", and I
might be influenced by past (and present) experience with
C/C++ compilers as Chris suggests.
But my second question was not adressed. Why doesn't the
compiler complain in this case:
class A implements B {
public A();
}
Class<?> clazz = Class.forName("A");
B b = (B) clazz.newInstance(); // Why is this safe?
Thanks!
Chris Uppal - 01 Feb 2006 10:06 GMT
> But my second question was not adressed. Why doesn't the
> compiler complain in this case:
[quoted text clipped - 5 lines]
> Class<?> clazz = Class.forName("A");
> B b = (B) clazz.newInstance(); // Why is this safe?
It seems to be because the compiler doesn't warn (or doesn't warn as often ?)
about casts to interfaces. When you are casting the result of Class.forName()
you are casting to a concrete type, and the compiler whinges about it. It
seems to think that mistakes are less likely with casts to interfaces (why ??).
For instance the following compiles without complaint:
Object o = new A("hello")
B b = (B) o;
Kind of arbitrary... (Which rather nicely illustrates my earlier point ;-)
-- chris
Thomas Hawtin - 01 Feb 2006 10:30 GMT
>> class A implements B {
>> B b = (B) clazz.newInstance(); // Why is this safe?
>
> It seems to be because the compiler doesn't warn (or doesn't warn as often ?)
> about casts to interfaces. When you are casting the result of Class.forName()
> you are casting to a concrete type, and the compiler whinges about it. It
> seems to think that mistakes are less likely with casts to interfaces (why ??).
I don't think it makes any difference whether the type is a class or an
interface.
> For instance the following compiles without complaint:
>
> Object o = new A("hello")
> B b = (B) o;
In that case, and the case above, you are casting to a type that can be
checked at runtime.
If you cast to a generic parameter type or a generic type then the cast
cannot be checked at runtime, hence the unchecked cast warning.
Some of the java.util code not only uses code that causes unchecked cast
warnings, but really allows a generic parameter type reference to point
to an incorrect type of object.
Tom Hawtin

Signature
Unemployed English Java programmer
http://jroller.com/page/tackline/
Chris Uppal - 01 Feb 2006 11:34 GMT
> > For instance the following compiles without complaint:
> >
[quoted text clipped - 3 lines]
> In that case, and the case above, you are casting to a type that can be
> checked at runtime.
No I'm not; 'o' is of declared type Object.
-- chris
Chris Uppal - 01 Feb 2006 12:00 GMT
I wrote:
> > > For instance the following compiles without complaint:
> > >
[quoted text clipped - 5 lines]
>
> No I'm not; 'o' is of declared type Object.
Sorry, I misread you; you said "runtime", not "compile time".
With that correction, I take your point.
I had not, in fact, realised that the compiler doesn't warn about
List<Object> list = ...
A a = (A)list.get(0);
Even more reason to avoid generics ;-)
-- chris
Tony Morris - 01 Feb 2006 21:57 GMT
> For instance the following compiles without complaint:
>
> Object o = new A("hello")
> B b = (B) o;
The misuse/warning of a parameterised type can be roughly interpreted as:
"You opted to use generic type-safety, but circumvented it with a cast - as
a result, I (the compiler) will issue you with a warning". In your above
case, it doesn't hold that you "opted to use generic type-safety",
therefore, you receive no warning.
Of course, you may choose to argue that the premise that I provided above is
somewhat contrived in that it doesn't meet a majority of use cases (or
whatever you might choose), in which case, I offer you the postulation that
you are just "scratching the surface" with respect to the defectiveness of
JSR-14.

Signature
Tony Morris
http://tmorris.net/