From: Fencer on 26 Mar 2010 05:36 Hello, consider the following program: package action; public class MyTest { public static void main(String[] args) { try { ClassLoader cl = MyTest.class.getClassLoader(); Class<?> c = cl.loadClass("action.SomeClass"); SomeClass inst = (SomeClass)c.newInstance(); System.out.println(inst); SomeClass inst2 = MyTest.loadClass("action.SomeClass"); System.out.println(inst2); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } public static <T> T loadClass(String className) { T inst = null; try { ClassLoader cl = MyTest.class.getClassLoader(); Class<?> c = cl.loadClass(className); inst = (T)c.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return inst; } } class SomeClass { @Override public String toString() { return "1337"; } } I'm getting a warning on line 27 for the following statement: inst = (T)c.newInstance(); The warning reads: Type safety: Unchecked cast from capture#4-of ? to T Ok, I think I get it. The compiler cannot know at compile time that the cast will work. But if you look at the code in the main method, I don't get a warning on line 11: SomeClass inst2 = MyTest.loadClass("action.SomeClass"); I thought the above line has the same problem as the one that is being warned about? I have two questions: 1. Why don't I get a warning for line 11 SomeClass inst2 = MyTest.loadClass("action.SomeClass"); ? 2. How should I rewrite the generic method loadClass? - Fencer
From: Steven Simpson on 26 Mar 2010 09:54 On 26/03/10 09:36, Fencer wrote: > 2. How should I rewrite the generic method loadClass? > public static <T> T loadClass(String className) { <T> T loadClass(Class<T> clazz, String className) > T inst = null; > try { > ClassLoader cl = MyTest.class.getClassLoader(); > Class<?> c = cl.loadClass(className); > inst = (T)c.newInstance(); inst = cl.loadClass(className).asSubclass(clazz).newInstance(); In the calling code: > SomeClass inst2 = MyTest.loadClass("action.SomeClass"); SomeClass inst2 = MyTest.loadClass(SomeClass.class, "action.SomeClass"); Note that you've already statically referred to action.SomeClass, so it's already loaded, and so there's no real point in doing anything dynamically (though I appreciate that this is a toy example). Normally, you'd specify a type that you expect the dynamically loaded class to extend or implement. In this case... > System.out.println(inst2); ....your only requirement on the loaded class is that it has the toString() method on it, as specified by Object, so you probably ought to write: Object inst2 = MyTest.loadClass(Object.class, "action.SomeClass"); So you're no longer referring to action.SomeClass statically. -- ss at comp dot lancs dot ac dot uk
From: markspace on 26 Mar 2010 12:31 Steven Simpson wrote: > On 26/03/10 09:36, Fencer wrote: >> System.out.println(inst2); > > ....your only requirement on the loaded class is that it has the > toString() method on it, as specified by Object, so you probably ought > to write: > > Object inst2 = MyTest.loadClass(Object.class, "action.SomeClass"); > > So you're no longer referring to action.SomeClass statically. > I think that the problem is expecting generics to do anything here. Given that the OP is trying to get a "known class" out of a string, how can he possibly do that? I think the should just admit that he can't and make the caller deal with it. public static Object loadClass( String className ) { ... is how I would declare that method. It's basically the same as the method Java provides on the Class object and, well, there's a reason for that. A more useful idea might be to assume that you have some type, some interface, that your string-named class is going to implement. Then you can at least check that the returned class implements that interface, even if you don't know its exact type at runtime. So here's another idea for "loadClass," which I've renamed here to make the example be a bit more clear: public static java.sql.Driver loadDB( String className ) { T inst = null; try { ClassLoader cl = MyTest.class.getClassLoader(); Class<?> c = cl.loadClass(className); inst = (java.sql.Driver)c.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return inst; } }
From: Lew on 26 Mar 2010 15:15 Stefan Ram wrote: > If everything else fails, I use > > @java.lang.SuppressWarnings( "unchecked" ) Note that if one's analysis is incorrect, i.e., that the types don't actually match, then the suppression of warnings defeats the purpose of generics, to eliminate ClassCastException. Suppressing the "unchecked" warning is reserved for times when the programmer has guaranteed that there cannot be a ClassCastException, but cannot satisfy the compiler that this is so, e.g., when using an expression like casting '(T)' to a parametrized type. If the programmer has not made that guarantee, then there's no point to suppressing the warning. -- Lew
From: Lew on 26 Mar 2010 15:29 Fencer wrote: > Hello, consider the following program: > > package action; > > public class MyTest { > > public static void main(String[] args) { > try { > ClassLoader cl = MyTest.class.getClassLoader(); > Class<?> c = cl.loadClass("action.SomeClass"); > SomeClass inst = (SomeClass)c.newInstance(); > System.out.println(inst); > SomeClass inst2 = MyTest.loadClass("action.SomeClass"); > System.out.println(inst2); > } catch (ClassNotFoundException e) { > e.printStackTrace(); > } catch (InstantiationException e) { > e.printStackTrace(); > } catch (IllegalAccessException e) { > e.printStackTrace(); > } > } > > public static <T> T loadClass(String className) { > T inst = null; > try { > ClassLoader cl = MyTest.class.getClassLoader(); > Class<?> c = cl.loadClass(className); > inst = (T)c.newInstance(); > } catch (ClassNotFoundException e) { > e.printStackTrace(); > } catch (InstantiationException e) { > e.printStackTrace(); > } catch (IllegalAccessException e) { > e.printStackTrace(); > } > > return inst; > } > > } > > class SomeClass { > @Override public String toString() { > return "1337"; > } > > } > > I'm getting a warning on line 27 for the following statement: > inst = (T)c.newInstance(); > The warning reads: > Type safety: Unchecked cast from capture#4-of ? to T > > Ok, I think I get it. The compiler cannot know at compile time that the > cast will work. But if you look at the code in the main method, I don't > get a warning on line 11: > SomeClass inst2 = MyTest.loadClass("action.SomeClass"); > I thought the above line has the same problem as the one that is being > warned about? > No, because here you are (unsafely) telling the compiler what the 'T' of the generic method is. > I have two questions: > 1. Why don't I get a warning for line 11 > SomeClass inst2 = MyTest.loadClass("action.SomeClass"); ? > Because the compiler infers 'T' from the declaration. 'ClassLoader#loadClass()' is not generically parametrized so cannot do that. > 2. How should I rewrite the generic method loadClass? > Well, you really don't give the method enough information to prevent a 'ClassCastException', so the generic parameter 'T' is essentially a lie. I'm not sure that you can reliably generify it without catching the 'ClassCastException'. -- Lew
|
Next
|
Last
Pages: 1 2 Prev: Hacking midlet signing Next: using path hint in javax.jnlp's openFileDialog |