5

I'm trying to use one of the simplest forms of reflection to create an instance of class:

package some.common.prefix;

public interface My {
    void configure(...);
    void process(...);
}

public class MyExample implements My {
    ... // proper implementation
}

String myClassName = "MyExample"; // read from an external file in reality

Class<? extends My> myClass =
    (Class<? extends My>) Class.forName("some.common.prefix." + myClassName);
My my = myClass.newInstance();

Typecasting unknown Class object we've got from Class.forName yields a warning:

Type safety: Unchecked cast from Class<capture#1-of ?> to Class<? extends My>

I've tried using instanceof check approach:

Class<?> loadedClass = Class.forName("some.common.prefix." + myClassName);
if (myClass instanceof Class<? extends RST>) {
    Class<? extends My> myClass = (Class<? extends My>) loadedClass;
    My my = myClass.newInstance();
} else {
    throw ... // some awful exception
}

but this yields a compilation error: Cannot perform instanceof check against parameterized type Class<? extends My>. Use the form Class<?> instead since further generic type information will be erased at runtime. So I guess I can't use instanceof approach.

How do I get rid of it and how am I supposed to do it properly? Is it possible to use reflection without these warnings at all (i.e. without ignoring or supressing them)?

GreyCat
  • 16,622
  • 18
  • 74
  • 112
  • 1
    Not sure what the strong typing is gaining you here. When you do Class.forName, there's no compile-time guarantee of the type of class that will result. You need to cast to (My) in any case. What extra compile-time safety does the typing gain you? – ewan.chalmers Apr 12 '11 at 15:32
  • 1
    I'm just playing goody-goody and eagerly want to know what kind of pot were Sun architects smoking while designing this warning. Looks like there's an answer afterall. – GreyCat Apr 13 '11 at 22:17

3 Answers3

5

This is how you do it:

/**
 * Create a new instance of the given class.
 * 
 * @param <T>
 *            target type
 * @param type
 *            the target type
 * @param className
 *            the class to create an instance of
 * @return the new instance
 * @throws ClassNotFoundException
 * @throws IllegalAccessException
 * @throws InstantiationException
 */
public static <T> T newInstance(Class<? extends T> type, String className) throws
        ClassNotFoundException,
        InstantiationException,
        IllegalAccessException {
    Class<?> clazz = Class.forName(className);
    Class<? extends T> targetClass = clazz.asSubclass(type);
    T result = targetClass.newInstance();
    return result;
}


My my = newInstance(My.class, "some.common.prefix.MyClass");
Simon G.
  • 6,587
  • 25
  • 30
  • 1
    A small hint. You can short the signature using a single throw ReflectiveOperationException. – Leo Sep 28 '16 at 13:22
  • 1
    @Leo - Agreed, provided one is on Java 7 or above. For Java 5 and 6, you need all three exception types – Simon G. Sep 29 '16 at 08:51
4

I think you can do it this way:

Class<? extends My> myClass= null;
Class<?> loadedClass = Class.forName("some.common.prefix." + myClassName);
if(My.class.isAssignableFrom(loadedClass))
{
    myClass = loadedClass.asSubclass(My.class);
}
My my = myClass.newInstance();
Justin Waugh
  • 3,975
  • 1
  • 21
  • 14
  • Nope, it doesn't work. Warning won't go away. Tried with javac 1.6.0_22 (from OpenJDK) and 1.6.0_24 (from Sun's JDK). – GreyCat Apr 12 '11 at 15:27
  • Odd, it compiles with no warnings in eclipse. What line is giving the warning? There is no cast in my code, so it can't be the same exception. – Justin Waugh Apr 12 '11 at 15:28
  • You don't get a warning in eclipse because the compiler has been instructed to suppress the unchecked cast warning. – tofarr Apr 12 '11 at 15:34
  • @Grey: You might not be able to avoid the warning, but what @Justin has given you is a runtime check that the loaded class is assignable to `My`, which allows you to properly and gracefully fail. At that point, just suppress the warning (`@SuppressWarnings("unchecked")`), there's no way around it and you've proven it to be irrelevant since if you make it to that code, you don't have a type problem. – Mark Peters Apr 12 '11 at 15:34
  • I don't get any warnings using jdk1.6.0_23 from sun. What exact warning are you getting? – Justin Waugh Apr 12 '11 at 15:46
  • Your current answer works okay, using `asSubclass()` to actually do a cast. I've accepted answer by Simon, because his answer appeared a bit earlier. Upvoting your answer as it's good too :) Thanks! – GreyCat Apr 13 '11 at 22:15
0

See this question How do I address unchecked cast warnings?. I have found that where reflection is concerned, you are best just to responsibly use @SuppressWarnings("unchecked")

Community
  • 1
  • 1
tofarr
  • 7,682
  • 5
  • 22
  • 30