Monday, June 27, 2011

Java Language Puzzle 2

Given the following source listing, explain why InstantiationException is thrown when running (via the main method entry point) and how the code should be fixed.

package puzzle;

public class Entity
{
    private Entity()
    {
    }
    
    public class Factory
    {
        public Entity create()
        {
            return new Entity();
        }
    }
    
    public static void main( String[] args ) throws Exception
    {
        Factory.class.newInstance();
    }
}
Exception in thread "main" java.lang.InstantiationException: puzzle.Entity$Factory
	at java.lang.Class.newInstance0(Unknown Source)
	at java.lang.Class.newInstance(Unknown Source)
	at puzzle.Entity.main(Entity.java:19)

ANSWER:  It looks like everyone who responded correctly identified the fact that Factory class is not defined as static as the cause of this exception. The solution is to add the static keyword. I would imagine that vast majority of Java developers are pretty comfortable with static/non-static inner classes semantics. What raises this to a puzzle level is a rather unhelpful exception.

15 comments:

Anonymous said...

Non-static inner class Factory is only reachable via an enclosing instance of Entity.

Fix by:
a) declaring inner class Factory as static
b) create Factory instance via an enclosing instance of entiy (but that would defeat the factories purpose)

Entity x = new Entity();
x.new Factory();

Greg A. said...

changing the factory declaration to this seems to work.

public static class Factory

I suppose the "reason" is that the static method of "main" can only reach other static declarations. If factory where its own top-level class, then it wouldn't need static.

w-cker said...

The new instance is missing an enclosing instance of Entity, unless Factory is declared as a static class.

Comentator said...

Because Factory is an inner class and there's no enclosing Entity instance?

Joachim Mairböck said...

My guess would be that the exception is thrown because Factory is a non-static inner class and therefore a Factory instance is bound to an Entity instance. Because there is no instance in the static main method, no Factory can be created.

The solution is simply to declare the Factory class static.

Bureck said...

My guess: As the factory class is a non-static inner class, it needs an instance of the outer class to exist. The main-method doesn't create an entity object. If you want to create a Factory instance in a "regular" way, by calling the constructor, you would need an Entity object and call the Factory constructor from there (e.g entity.new Factory()). To instantiate the inner class via reflection, I guess you have to get a suitable constructor using Factory.class.getConstructors() and get pass an instance of the outer class when calling it.

Anonymous said...

Creating an instance of Factory requires an enclosing instance of Entity.

Perhaps the intent was to make Factory a static inner class?

Ian Bull said...

It's because there is no Enclosing instance of type Entity. You can make Factory static, but that might not be what's desired.

If you replace Factory.class.newInstance() with new Factory(), you can see this as a compile time error. You can use new Entity().new Factory().

If you want to leave Factory as a non-static inner class and still use reflection to instantiate it... well I'm not sure how to do that... looking forward to the answer.

Anonymous said...

package puzzle;

public class Entity
{
private Entity()
{
}

public static class Factory
{
public Entity create()
{
return new Entity();
}
}

public static void main( String[] args ) throws Exception
{
Factory.class.newInstance();
}
}

CK said...

non-static inner classes need to be instanced from an instance of their outer class, since they keep a reference to the outer class in a compiler-generated field called "outer".
In this case, you could either:

- Create a Factory instance from an Entity object: new Entity().new Factory()
- change the inner class to be static, so it doesn't require an instance of the outer class to be instantiated

konberg said...

Factory isn't a static class, needs an instance of Entity in order to instantiate it. Possibly make it static, possibly use Constructor.newInstance() and supply an Entity.

Rui Figueira said...

InstanciationException is thrown because Factory is a inner class of Entity and therefore it can only be instanciated inside a non-static method of Entity. That code can be fixed by converting Factory to a static class.

joakime said...

Make the Factory class static so that you don't need an instance of Entity to create it.

public static class Factory

Brendan said...

Add the "static" modifier to the inner Factory class.

konberg said...

I just verified that my guess was correct. The following works:

Entity entity = Entity.class.newInstance();
Factory factory = Factory.class.getConstructor(Entity.class).newInstance(entity);
Entity otherEntity = factory.create();