简体   繁体   中英

Java abstract parent calling child method before child is initialized in parent constructor

I have the following classes:

abstract class Parent
{
    private ClassDependentOnSize classDependentOnSize;

    public Parent ()
    {
        this.classDependentOnSize = new ClassDependentOnSize(size());
    }

    public abstract int size ();
}

class Child extends Parent
{
    private String DBSelection;
    private String[] DBSelectionArgs;

    public Child (String selection, String... selectionArgs)
    {
        super();
        this.DBSelection = selection;
        this.DBSelectionArgs = selectionArgs;
    }

    @Override
    public int size()
    {
        //FAILS because Parent calls size before DBSelectionArgs is initialized
        String temp = "";
        for(String str : DBSelectionArgs)
           temp += str;
        return temp.length;

        //This function basically does a calculation that should not be
        //done before hand. I have posted the exact method below.
    }
}

class ClassDependentOnSize 
{
    public ClassDependentOnSize(int size)
    {

    }
}

While this are not my exact class, this is the same problem. I have written this one to remove all the unnecessary code.

As you can see, the super class tries to call size () before the child is finished initializing to construct the class dependent on size. I am curious on how anyone has resolved this in the past. As I am sure everyone is aware, super() must be the first line in a child constructor. As I have laid these classes out, is this a bad design? I feel like this is a problem that must have happened before, but I can not find a solution.

EDIT: Here is the exact method. It uses for an Android application.

protected Cursor getCursor()
{
    if (songCursor == null)
    {
        songCursor = GET_SONGS_CURSOR(getContext(), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString(), selection, selectionArgs, selection);

        if (!songCursor.moveToFirst())
            Standard.Loge("|NewPlaylist.getCursor| Could not move to first.");
    }

    int count = songCursor.getCount();
    songCursor.close();
    return count;
}

A simple solution for your specific case is to pass the size as an argument to the parent constructor.

This of course assumes that your real problem has the same characteristics, namely that all the information needed by the base class constructor are available when calling the constructor.

I've definitely had this problem before. The takeaway lesson is that you should never call non-private methods in the Parent constructor so this doesn't happen

Changing parent to take in the size as an argument is one option:

public Parent (int size)
{
    this.classDependentOnSize = new ClassDependentOnSize(size);
}

...

public Child (String selection, String... selectionArgs)
{
    super(selectionArgs.length);
    this.DBSelection = selection;
    this.DBSelectionArgs = selectionArgs;
}

Another option, which is a bit of a hack, is to have an init method that must be called after construction:

abstract class Parent
{
    private ClassDependentOnSize classDependentOnSize;

    public final void init()
    {
        this.classDependentOnSize = new ClassDependentOnSize(size());
    }

    public abstract int size ();
}

...

public Child (String selection, String... selectionArgs)
{
    this.DBSelection = selection;
    this.DBSelectionArgs = selectionArgs;
    init();
}

The right answer here is likely to change the structure your code, but, without more concrete details, I can't provide meaningful feedback as to how you want to go about that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM