Let's assume I have a base class Fruit
public class Fruit {
String name;
public Fruit(String name) {
this.name = name
}
}
And that I have class Apple()
which extends Fruit()
and I give that class two constructors.
public class Apple extends Fruit {
// constructor one
public Apple() {
this("Apple");
}
// constructor two
public Apple(String name) {
super(name);
}
}
This lets me call new Apple()
as well as new Apple("Red Apple")
Rather than having to add constructor one
to each derived class of Fruit
, I would prefer that Fruit
resemble the following:
public class Fruit {
String name;
// Automatically assign the classname from the derived class
public Fruit() {
this(this.getClass().getSimpleName());
}
public Fruit(String name) {
this.name = name
}
}
And then I could remove constructor one
from Apple
as it would be inheritted from Fruit
Ideally, this would let me call new Apple()
and automatically set Apple.name
to Apple
Unfortunately, this(this.getClass().getSimpleName());
throws an error of
java cannot refer to 'this' nor 'super' while explicitly invoking a constructor
I use a similar pattern in other languages without any issues. How do I assign the derived class name as a param within the base class constructor? Is something like this even possible in Java?
And then I could remove constructor one from Apple as it would be inheritted from Fruit
No, you wouldn't. That's not how java works. Trivial example:
class Parent {
private final String name;
public Parent() {
this("Jane");
}
public Parent(String name) {
this.name = name;
}
}
class Example extends Parent {
public Example(String name) {
super(name);
}
static void test() {
new Example(); // compiler error
}
}
In java, constructors do not inherit. Methods inherit - if you class Y extends X
where X contains some method, then Y also contains that method, automatically (in fact, you can't 'remove it', at best, you can override it). But constructors simply do not do that. Y can call them, using super
syntax. That's where it ends.
But, this might be confusing! There are 2 unrelated java language features that make it look like constructors inherit, but they don't:
If your class does not have a constructor at all, then java will assume you meant to write public YourClassName() {}
- as in, java will act as if you have a public no-args do-nothing constructor.
All constructors are required to invoke either this
or super
, they can't not. If you fail to do it, the compiler assumes you intended to start your constructor off with super()
. This rule applies to the previous bullet, too.
So, given:
class Example {
Example() {
System.out.println("In example constructor");
}
}
class Child extends Example {
}
class Main {
public static void main(String[] args) {
new Child(); // prints 'In example constructor'
}
}
But, make no mistake, this has nothing to do with Child 'inheriting' a constructor. It does not. There is no constructor defined so java plays a game of make believe and acts as if you write public Child() { super(); }
.
Your question is therefore almost entirely obviated now.
But, for argument's sake:
You simply can't. Not how java works. However, the solution is generally instead to work with sentinels. Fields should be private
, not package private or protected. That gives us full control over it. If you want others to access the 'field', make a getter. Because you control that.
Now that it is private, we can decree that if the string is a certain value, that means to just inherit the name. Thus:
public class Fruit {
private final String name;
public Fruit() {
this.name = null;
}
public Fruit(String name) {
if (name == null) throw new NullPointerException("name");
this.name = name;
}
public String getName() {
return this.name != null ? name : this.getClass().getName();
}
}
Here, everywhere name is relevant, we check the field: if it is null, we return the class name. Otherwise we return the field.