![]() |
|
|
|
#1 |
|
"Jacob" <> wrote in message
news:MKidnQIqzM-... > 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! > 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.acti...owAnswers=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 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/ Tony Morris |
|
|
|
|
#2 |
|
Posts: n/a
|
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! |
|
|
|
#3 |
|
Posts: n/a
|
Jacob wrote:
> 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 |
|
|
|
#4 |
|
Posts: n/a
|
On Tue, 31 Jan 2006 09:35:32 +0100, Jacob <> wrote, quoted or indirectly quoted someone who said : >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.. -- Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching. |
|
|
|
#5 |
|
Posts: n/a
|
Jacob wrote:
> 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. 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 -- ================================================== ====================== Ian Pilcher ================================================== ====================== |
|
|
|
#6 |
|
Posts: n/a
|
Jacob wrote:
> 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! |
|
|
|
#7 |
|
Posts: n/a
|
Jacob wrote:
> 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? 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 |
|
|
|
#8 |
|
Posts: n/a
|
Chris Uppal wrote:
> Jacob wrote: > >> 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 -- Unemployed English Java programmer http://jroller.com/page/tackline/ |
|
|
|
#9 |
|
Posts: n/a
|
Thomas Hawtin wrote:
> > 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. No I'm not; 'o' is of declared type Object. -- chris |
|
|
|
#10 |
|
Posts: n/a
|
I wrote:
> Thomas Hawtin wrote: > > > > 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. > > 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 |
|