views:

3284

answers:

3

I have a some simple Java code that looks similar to this in it's structure:

abstract public class BaseClass {
    String someString;
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public ASubClass(String someString) {
        super(someString);
    }
    public String getName() {
        return "name value for ASubClass";
    }
}

I will have quite a few subclasses of BaseClass, each implementing the getName() method in their own way (template method pattern).

This works well, but I don't like having the redundant constructor in the subclasses. It's more to type and it is difficult to maintain. If I were to change the method signature of the BaseClass constructor, I would have to change all the subclasses.

When I remove the constructor from the subclasses, I get this compile-time error:

Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor

Is what I am trying to do possible?

+2  A: 

It is possible but not the way you have it.

You have to add a no-args constructor to the base class and that's it!

public abstract class A {
 private String name;
 public A(){
  this.name = getName();
 }
 public abstract String getName();


 public String toString(){
  return "simple class name: " + this.getClass().getSimpleName() + " name:\"" + this.name + "\"";
 }
}
class B extends A {
 public String getName(){
  return "my name is B";
 }
 public static void main( String [] args ) {
  System.out.println( new C() );
 }
}
class C extends A {
 public String getName() {
  return "Zee";
 }
}

When you don't add a constructor ( any ) to a class the compiler add the default no arg contructor for you.

When the defualt no arg calls to super(); and since you don't have it in the super class you get that error message.

That's about the question it self.

Now, expanding the answer:

Are you aware that creating a subclass ( behavior ) to specify different a different value ( data ) makes no sense??!!! I hope you do.

If the only thing that is changes is the "name" then a single class parametrized is enough!

So you don't need this:

MyClass a = new A("A");
MyClass b = new B("B");
MyClass c = new C("C");
MyClass d = new D("D");

or

MyClass a = new A(); // internally setting "A" "B", "C" etc.
MyClass b = new B();
MyClass c = new C();
MyClass d = new D();

When you can write this:

MyClass a = new MyClass("A");
MyClass b = new MyClass("B");
MyClass c = new MyClass("C");
MyClass d = new MyClass("D");

If I were to change the method signature of the BaseClass constructor, I would have to change all the subclasses.

Well that's why inheritance is the artifact that creates HIGH coupling, which is undesirable in OO systems. It should be avoided and perhaps replaced with composition.

Think if you really really need them as subclass. That's why you see very often interfaces used insted:

 public interface NameAware {
     public String getName();
 }



 class A implements NameAware ...
 class B implements NameAware ...
 class C ... etc.

Here B and C could have inherited from A which would have created a very HIGH coupling among them, by using interfaces the coupling is reduced, if A decides it will no longer be "NameAware" the other classes won't broke.

Of course, if you want to reuse behavior this won't work.

OscarRyz
Yes, except you can no longer ensure that your instances are initialized properly (e.g. have names in this particular case)
ChssPly76
@ChssPly76 : Yes, but that's probably because the inheritance is being used in a poorly way. I expanded my answer to cover it.
OscarRyz
+7  A: 

You get this error because a class which has no constructor has a default constructor, which is argument-less and is equivalent to the following code:

public ACSubClass() {
    super();
}

However since your BaseClass declares a constructor (and therefore doesn't have the default, no-arg constructor that the compiler would otherwise provide) this is illegal - a class that extends BaseClass can't call super(); because there is not a no-argument constructor in BaseClass.

This is probably a little counter-intuitive because you might think that a subclass automatically has any constructor that the base class has.

The simplest way around this is for the base class to not declare a constructor (and thus have the default, no-arg constructor) or have a declared no-arg constructor (either by itself or alongside any other constructors). But often this approach can't be applied - because you need whatever arguments are being passed into the constructor to construct a legit instance of the class.

matt b
Thank you so much. Your explanation makes total sense and this was really confusing me.
JDelage
A: 

your BaseClass needs a someString so deliver one.
Try this:

abstract public class BaseClass {
    String someString;
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public ASubClass() {
        super("someString");  // or a meaningfull value, same as getName()?
    }
    public String getName() {
        return "name value for ASubClass";
    }
}

or

abstract public class BaseClass {
    String someString;
    protected BaseClass() {  // for subclasses
        this.someString = null;  // or a meaningfull value
    }
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public String getName() {
        return "name value for ASubClass";
    }
}
Carlos Heuberger