Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I force a Constructor to be defined in all subclass of my abstract class

I have an abstract class A that define abstract methods. This means that, for a class to be instanciable, all the abstract method have to be implemented.

I'd like all my subclasses to implement a constructor with 2 ints as parameters.

Declaring a constructor defeats my purpose, as I want the constructor defined in subclasses and I don't know anything about the implementation. Moreover I cannot declare a constructor as being abstract;

Is there a way to do this ?

Example of what I want:

Lets say that I am defining the API of a Matrix class. In my problem, Matrix cannot change their dimensions.

For a Matrix to be created, I need to provide its size.

Hence, I want all my implementors to provide the constructor with the size as a parameter. This constructor is motivated by the problem, not by an implementation concern. The implementation can do whatever it wants with these, provided that all the semantic of the methods are kept.

Let's say I want to provide a basic implementation of the invert() method in my abstract class. This method will create a new matrix with this inverted dimensions. More specifically, as it is defined in the abstract class, it will create a new instance of the same class as this, using a constructor that takes two ints. As it does not know the instance it will use reflection (getDefinedConstructor) and I want a way to waranty that I'll get it and that it will be meaningfull for the implementation.

like image 627
dodecaplex Avatar asked Jul 02 '10 08:07

dodecaplex


People also ask

Can I define constructor in abstract class?

Yes, an Abstract Class can have a Constructor. You Can Overload as many Constructor as you want in an Abstract Class. These Contractors Can be used to Initialized the initial state of the Objects Extending the Abstract Class.

How do you call a constructor from an abstract class?

You can't call an abstract class constructor with a class instance creation expression, i.e. As constructors of abstract classes can only be called within subclass constructors (and by chaining one to another within the same class), I typically make them protected ... making them public would serve no purpose.

How do you call a constructor from a subclass?

To explicitly call the superclass constructor from the subclass constructor, we use super() . It's a special form of the super keyword. super() can be used only inside the subclass constructor and must be the first statement.

Can constructors be inherited in abstract class?

Yes, an abstract class can have a constructor in Java. You can either explicitly provide a constructor to the abstract class or if you don't, the compiler will add a default constructor of no argument in the abstract class.


2 Answers

You can't force a particular signature of constructor in your subclass - but you can force it to go through a constructor in your abstract class taking two integers. Subclasses could call that constructor from a parameterless constructor, passing in constants, for example. That's the closest you can come though.

Moreover, as you say, you don't know anything about the implementation - so how do you know that it's appropriate for them to have a constructor which requires two integers? What if one of them needs a String as well? Or possibly it makes sense for it to use a constant for one of those integers.

What's the bigger picture here - why do you want to force a particular constructor signature on your subclasses? (As I say, you can't actually do this, but if you explain why you want it, a solution might present itself.)

One option is to have a separate interface for a factory:

interface MyClassFactory {     MyClass newInstance(int x, int y); } 

Then each of your concrete subclasses of MyClass would also need a factory which knew how to build an instance given two integers. It's not terribly convenient though - and you'd still need to build instances of the factories themselves. Again, what's the real situation here?

like image 112
Jon Skeet Avatar answered Oct 11 '22 07:10

Jon Skeet


You could try something like below. The constructor will thrown an exception if the implementing class does not have a constructor with the appropriate arguments.

This is silly. Compare OK and Bad. Both classes are the same, except that OK meets your requirement and thus passes the runtime checks. Thus enforcing the requirement promotes counter-productive busy work.

A better solution would be some sort of Factory.

abstract class RequiresConstructor {     RequiresConstructor( int x, int y ) throws NoSuchMethodException     {     super();     System.out.println( this.getClass().getName() ) ;     this.getClass(). getConstructor ( int.class , int.class ) ;     }      public static void main( String[] args ) throws NoSuchMethodException     {     Good good = new Good ( 0, 0 );     OK ok = new OK ();     Bad bad = new Bad ();     } }  class Good extends RequiresConstructor {     public Good( int x, int y ) throws NoSuchMethodException     {     super( x, y ) ;     } }  class OK extends RequiresConstructor {     public OK( int x, int y ) throws NoSuchMethodException     {     super( x, y ) ;     throw new NoSuchMethodException() ;     }      public OK() throws NoSuchMethodException     {     super( 0, 0 ) ;     } }  class Bad extends RequiresConstructor {     public Bad() throws NoSuchMethodException     {     super( 0, 0 ) ;     } } 
like image 29
emory Avatar answered Oct 11 '22 05:10

emory