Reputation: 8591
I have a parent class
public class Parent
{
Database m_d;
Parent(Database d){
m_d = d;
}
}
And a child class
public class Child extends Parent implements java.lang.AutoCloseable
{
ChildDatabase m_d
Child()
{
// Error on the next statement:
// "Cannot reference m_database before supertype constructor
// has been called"
super(m_d = CreateDatabase());
}
}
Note that ChildDatabase
implements java.lang.AutoCloseable
which is a reason why I need to keep a ChildDatabase
reference in the Child
class. Note that ChildDatabase
extends Database
.
The problem is that super(m_d = CreateDatabase());
is not valid since you can't refer to child class members in the call to super
.
Is there a syntax I'm missing which would allow me to do this? An alternative would be to implement a getDatabase()
method in Parent
, and cast that result to a ChildDatabase
to store as m_d;
, but that seems a smell to me.
Note that CreateDatabase
can be static
.
Upvotes: 2
Views: 103
Reputation: 131346
By introducing a getter of the object in the parent class you could write it :
public class Child extends Parent implements java.lang.AutoCloseable
{
ChildDatabase m_d;
Child()
{
// Error on the next statement:
// "Cannot reference m_database before supertype constructor
// has been called"
super(CreateDatabase());
this.m_d = (ChildDatabase)getMd();
}
}
But the downcast is undesirable, it may fail at runtime and it looks a hack.
If the subclass needs to refer to the field as a ChildDataBase
, it should be explicit in the constructor itself such as :
ChildDatabase m_d;
Child(ChildDatabase childDb)
{
super(childDb);
m_d = childDb;
}
In a general way dependencies should be explicit if not an implementation detail since It favors the testability and the switch to other implementations.
Note that I don't like either a lot this solution.
This still duplicates the field in the hierarchy.
The problem here is that you want to value the same object with for the parent constructor and the child constructor a distinct declared type.
You should not. It is error prone for people reading your code.
Using a generic class is probably better and would allow subclasses to specify the subclass for Database fields.
It will still require to provide the getter in the parent class.
public class Parent<T ? extends DataBase>
{
private T m_d;
Parent(T d){
m_d = d;
}
public T getMd(){
return m_d;
}
}
With hidden dependency :
public class Child extends Parent<ChildDataBase> implements AutoCloseable
{
Child(){
super(CreateDatabase());
}
void foo(){
ChildDataBase md = getMd(); // return the generic type
}
}
With exposed dependency :
public class Child extends Parent<ChildDataBase> implements AutoCloseable
{
Child(ChildDataBase md){
super(md);
}
void foo(){
ChildDataBase md = getMd(); // return the generic type
}
}
Upvotes: 0
Reputation: 2148
Why do you want to have the field m_d
in both Parent
and Child
? Isn't it sufficient to have it only in Parent
? And simply have super(createDatabase());
in Child
's constructor like in below code:
public class Parent
{
Database m_d;
Parent(Database d)
{
m_d = d;
}
}
class Child extends Parent implements java.lang.AutoCloseable
{
Child()
{
super(createDatabase());
}
private static ChildDatabase createDatabase()
{
return new ChildDatabase();
}
@Override
public void close() throws Exception
{
}
}
class Database
{
}
class ChildDatabase extends Database implements java.lang.AutoCloseable
{
@Override
public void close() throws Exception
{
}
}
Upvotes: 0
Reputation: 16354
What you are trying to achieve is simply not feasible.
Following the Java language specification, no class field member can be initialized before the call to super
(constructor) has been done.
As you are implementing a specific behavior within your Child
class, a workaround, may be to omit the local m_d
field passing the desired Database
instance reference over a factory mixed with a generic formal type for the sub-type Database
.
Here down the Parent
class type:
public class Parent<D extends Database> {
D m_d;
Parent(D m_d) {
m_d = m_d;
}
protected D getDatabase() {
return this.m_d;
}
}
And the Child
would be as follows:
public class Child extends Parent<ChildDatabase> {
private Child(ChildDatabase m_d) {
super(m_d);
}
private static ChildDatabase createDatabase() {
return null;
}
public static class ChildFactory {
public static Child createChild() {
return new Child(createDatabase());
}
}
}
Upvotes: 0
Reputation: 5290
How about
public abstract class Parent<DB extends Database>
{
DB m_d;
Parent()
{
m_d = getDatabase();
}
abstract DB getDatabase();
}
and
public class Child extends Parent<ChildDatabase> implements java.lang.AutoCloseable
{
Child()
{
// do something with this.m_d here
}
@Override
ChildDatabase getDatabase()
{
return createChildDatabase();
}
}
Then you can even use AutoCloseable features directly on this.m_d (like try...with etc).
Upvotes: 2