views:

401

answers:

8

Suppose I have a base class B, and a derived class D. I wish to have a method foo() within my base class that returns a new object of whatever type the instance is. So, for example, if I call B.foo() it returns an object of type B, while if I call D.foo() it returns an object of type D; meanwhile, the implementation resides solely in the base class B.

Is this possible?

+3  A: 

As long as each class has a default constructor:

    public B instance() throws Exception {
        return getClass().newInstance();
    }
Garth Gilmour
This works, but don't declare methods that throw the generic "Exception" class.
jsight
I take the opposite approach - only declare multiple exceptions when the client would a) care and b) recover from the differently. Otherwise its just visual clutter e.g. demos and JUnit tests...
Garth Gilmour
+1  A: 

I think this might be possible to do using reflection, i.e. in your superclass you have:

public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
    return getClass().newInstance();
}

Where ClassName is the name of your base class.

You'll have to cast it wherever you want to use it though... I'm not sure this is really a great solution!

Edit: newInstance() type methods are usually static, and of course you won't have an idea of what the type of your subclass is with a static method.

I don't think there's any way of getting a static method to (dynamically) create an instance of a subclass.

Phill Sacre
+1  A: 

Well, I could be off but I would assume that since "this" always refers to the current object, you could do something like

public B foo() {
    return this.getClass().newInstance();
}

or something along those lines? If you create an instance of D and then call d.foo() you should get an instance of D returned as a B. You could return it as a plain Object but you should be as specific as possible in this instance, I think.

MattC
A: 

@Rik

Well, the real problem is that I have a abstract base class Thing. And Thing has a method called getNextThing() which returns a new instance of Thing.

Then, I have a number of subclasses like BigThing, LittleThing, SomethingThing, and I don't want to keep rewriting the getNextThing() method for each of them. It seems wasteful, since they all do the same... thing.

Am I incorrect in my approach?

Jake
No, using the reflection answers given to your question, you should be able to implement this how you want, which seems fine to me.
MattC
I think you're gonna have to go with reflection then.
Rik
"It seems wasteful, since they all do the same... thing." It's rarely wasteful. You have subclasses for a reason. Often, each subclass has a different constructor or initialization or something. They're rarely identical.
S.Lott
Reflection will only work if you have a default constructor. Using the reflection approach will work, but only under that condition, which makes it rather error prone when creating subclasses.
Robin
Understood. Thanks for everyone's help!
Jake
A: 

I'm not sure why you're trying to do what you're actually trying to do. Providing more of a context might let us give you more help.

public class B <X extends B>{

public X foo() throws InstantiationException, IllegalAccessException{
    return (X)this.getClass().newInstance();
}
}        
public class C extends B<C>{        

}

Let me offer you this piece of advice. The way CS classes tend to be taught is that professors are enamored with inheritance, but haven't figured out composition. I think What you might be looking for is composition. So instead of calling getNextThing on the Thing itself, maybe you should think about making Thing implement Iterable

This means you will just need to write an Iterator that can encapsulate the logic of getting the next thing, as it doesn't seem to fit into your inheritance model. Another advantage of this is that you get some nice syntactic devices out of this (enhanced for loop comprehension).

Steve g
+1  A: 

Apart from the fact that I think there probably is a design flaw if you want to accomplish this, you could try the following approach.

In your question, you are using static (class) methods, B.foo(), D.foo(), this cannot be accomplished using inheritance because the static methods do not have a dynamic nature, they do not take part in the lookup system. So you don't have enough type information.

If you are using a member function foo() you could have the following construct:

public class B {
    public B foo()
    throws IllegalAccessException, InstantiationException {
        return this.getClass().newInstance();
    }
}

public class D  extends B{    
}

public class Test {
    public static final void main(String[] args)
    {
        try {
            System.out.println((new B()).foo());
            System.out.println((new D()).foo());
        } catch (IllegalAccessException e) {
            e.printStackTrace();  
        } catch (InstantiationException e) {
            e.printStackTrace();  
        }
    }
}
Bruno Ranschaert
Sorry, I did not mean to imply that foo() was a static method. It is not.
Jake
Also, why do you believe this is the product of a design flaw?
Jake
+1  A: 

As the other answers say, you can use getClass().newInstance() if there is a no-argument constructor in each subclass (make sure to catch InstantiationException and IllegalAccessException).

If any of the constructors require arguments, you can either use reflection or (preferable in my view) define a method like getNewInstance() which you can override in the subclass only if needed.

e.g.

Thing foo() {
    Thing th = getNewInstance();
    // do some stuff with th
    return th;
}

Thing getNewInstance() {
    return getClass().newInstance();
}

Then getNewInstance() can be overridden only if you really need to, for subclasses that don't have the default constructor.

Thing getNewInstance() {
    return new BigThing(10, ThingSize.METRES);
}
Leigh Caldwell
+3  A: 

Don't. Make the "foo" method abstract.

abstract class B {
    public abstract B foo();
}

Or receive an abstract factory through the base class constructor:

abstract class B {
    private final BFactory factory;
    protected B(BFactory factory) {
        this.factory = factory;
    }
    public B foo() {
        return factory.create();
    }
}
interface BFactory {
    B create();
}

Add covariant return types and generics to taste.

Tom Hawtin - tackline