Compiler knows that AbstractDemo
is an abstract class and Abstract classes can't be instantiated.
But when I call newInstance()
method, why it did not give a compile time error?
import java.lang.reflect.Constructor;
public abstract class AbstractDemo{
public AbstractDemo(){
System.out.println("Default constructor");
}
public static void main(String args[]){
try{
/* No compilation error for this statement */
AbstractDemo demo = AbstractDemo.class.newInstance();
Constructor[] ctors = AbstractDemo.class.getDeclaredConstructors();
for ( int i=0; i < ctors.length; i++){
System.out.println(ctors[i]);
/* No compilation error for this statement too */
AbstractDemo demo1 = (AbstractDemo) ctors[i].newInstance();
}
/* Compilation error here */
// AbstractDemo demo2 = new AbstractDemo();
}catch(Exception err){
err.printStackTrace();
}
}
}
Output when I ran this program: ( I know that error will come since I can't create instance for abstract class. But why it was not given at compile time is surprising me)
D:\Study\Java>java AbstractDemo
java.lang.InstantiationException
at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at java.lang.Class.newInstance(Class.java:374)
at AbstractDemo.main(AbstractDemo.java:10)
EDIT:
Compiler is intelligent to give error for this statement:
AbstractDemo demo2 = new AbstractDemo();
But not for this statement
AbstractDemo demo = AbstractDemo.class.newInstance();
Am I missing any key lesson here?
The compiler's job is to check compile-time rules (er, and compile the code). The method you're calling is Class#newInstance
, not anything related (directly) to AbstractDemo
. The fact that Class#newInstance
will throw (because the instance of Class
on which you call it is for an abstract class) is a runtime concern.
While it might, in theory, be possible sometimes to determine at compile-time that a particular reference to a particular instance of Class
refers to an abstract class (such as AbstractDemo.class
), usually it won't be possible, for instance:
void someMethodInMyOwnClass(Class c) {
Object o = c.newInstance();
}
And even if it were, then we'd need some kind of built-in rule or annotation system (e.g., compile-time information) saying "This method of this class can't be called if the Class
instance refers to an abstract class."
So we're talking about non-trivial work, and there's no real value in doing that work, making it sometimes a compile-time error and other times a runtime error.
Consider: The compiler could also work out that this throws an NPE:
String s = null;
if (s.equalsIgnoreCase("foo")) {
// ...
}
Or that the body of this loop will never be executed:
int x = 10;
while (x < 10) {
System.out.println("Never gets here");
}
But we don't have it do so; those are runtime concerns.