Difference between newInstance and constructor for private inner classes
Hi I have an interesting problem.
I expected the same behaviour for newInsance and for a constructor.
But the constructor access modifier is not handled the same.
Can some one explain this?
Thanks
publicclass Test
{
publicstaticvoid main(String[] args)
{
new Test().run();
}
privatevoid run()
{
try
{
MyClass myClass=new MyClass();
myClass.todo();
MyClass myClass1= (MyClass)(MyClass.class.newInstance());//fails here. Why?
myClass1.todo();
}
catch (Exception e)
{
e.printStackTrace();
}
}
privatestaticclass MyClass
{
publicvoid todo()
{
System.out.println("MyClass.todo");
}
}
}
This was tested with jdk 1.4.2_11 on Windows
[1796 byte] By [
ebommfa] at [2007-10-3 4:52:54]

change the class modifier from private to public
Well I figured that out, but the question is still why?
From the philosophy of the code, the constructor should be private. The direct call to the constructor shows that it works.
I can further add that the eclipse compiler changes the visibility the constructor from private to default. I.e., if you compile from within eclipse, it works while the ant build produces an exception.
Is this the behaviour that was intented? Is it a bug?
Thanks for comments
i guess i have to ask, why bother using newInstance() over new()?
In the original code, it is a factory, where I choose a class from a Map without knowing its type in advance. I cast it to an interface. There are various possible workaround (I changed the visisbility of the constructor as you suggested).
I would still apreciate more comments on this topic
Frank
You could also add a public default constructor MyClass() to make it work.
I'd guess, it's because for newInstance() the constructor reference is solved at runtime, while for new MyClass() it is solved at compile time. Another indicator could be, that it is allowed to call newInstance() on MyClass.class, even if MyClass is private, but the constructor of MyClass is private, too, hence calling the constructor fails.
> Well I figured that out, but the question is still
> why?
It is complicated and an exact answer would require specifically and very carefully stepping through the rules of the JLS spec.
Basically in one case the access is via the method (the new expression.)
In the other case the access is via a class (java.lang.Class) which does not have access.
> In the other case the access is via a class (java.lang.Class) which does not have access.This does not explain then why a default constructor works. If the call is made via the class (java.lang.Class), the constructor should be public and would fail for all other access
> This does not explain then why a default constructor> works. What is the access modifier on a default constructor?
The answer is this. Since the modifier on MyClass is private, even class Test is not legally allowed to access its constructor by the runtime. If you put the normal new statement into the code, the compiler creates a synthetic method in MyClass that accesses the constructor properly and has a default modifier instead of private. If you access it via reflection, the compiler has no cue to create the synthetic method and you're left without accessibility to your private class. Hope that helps.
you cannot use class.newInstance to instantiate an inner class, if memory serves me correctly. you can use Constructor.newInstance, but be aware that an inner class has an implicit constructor that accepts it's enclosing type as an argument. eg:
public class MyClass {
private void run() throws Exception {
MyInner inner = MyInner.class.newInstance();
}
public static void main(String[] args) throws Exception {
new MyClass().run();
}
public class MyInner {
}
}
will not run, neither will this
import java.lang.reflect.Constructor;
public class MyClass {
private void run() throws Exception {
Constructor<MyInner> constructor = MyInner.class.getDeclaredConstructor(new Class[0]);
MyInner inner = constructor.newInstance(new Object[0]);
}
public static void main(String[] args) throws Exception {
new MyClass().run();
}
public class MyInner {
}
}
but this will
import java.lang.reflect.Constructor;
public class MyClass {
private void run() throws Exception {
Constructor<MyInner> constructor = MyInner.class.getDeclaredConstructor(new Class[] { MyClass.class });
MyInner inner = constructor.newInstance(new Object[] { this });
}
public static void main(String[] args) throws Exception {
new MyClass().run();
}
public class MyInner {
}
}
Message was edited by:
georgemc
your inner class is private, which won't help, either. didn't spot that :-)
Well, there is another major difference from your posting to the OP's: you are using a non-static inner class, which complicates things a bit :)
indeed it does. off the top of my head, I can't be sure what the rules are, but it seems the OP has got a hold of the JLS anyway
you need the instance of the outer class for creating an inner class.
Otherwise for which instance of the Outer Class will the inner class be created.
For example:
BuildConfigurationEntity bce = (BuildConfigurationEntity) Class.forName("cfg.com.BuildConfigurationEntity").newInstance();
Class cs = Class.forName("cfg.com.BuildConfigurationEntity$Project");
Constructor[] csr = cs.getDeclaredConstructors();
csr[0].newInstance(new Object[]{bce});
The above example is for creating the inner class outside the outer class. If you want to create it in the outer class itself you can use "this"