Sahand
Sahand

Reputation: 8360

Constructor of superclass is entered without me wanting it to

I have a class PageRankMonteCarlo that extends PageRankSparse. PageRankMonteCarlo has a constructor which is called in main(). Inside of the constructor, PageRankSparse.readDocs() is called, to set up some variables of the PageRankMonteCarlo object.

When I run PageRankMonteCarlo, the constructor of PageRankSparse is executed, even though I don't want it to. This leads to readDocs being called twice, since readDocs is also called in PageRankSparse(). Here's the code:

PageRankMonteCarlo.java:

package pagerank;

public class PageRankMonteCarlo extends PageRankSparse {

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Please provide a filename");
        }
        new PageRankMonteCarlo(args[0]);
    }

    public PageRankMonteCarlo(String filename) {
        NUMBER_OF_DOCS = readDocs(filename);
        System.out.printf("NUMBER_OF_DOCS: %d\n", NUMBER_OF_DOCS);

    }
}

PageRankSparse.java:

public class PageRankSparse {


    public PageRankSparse( String filename ) {
    int noOfDocs = readDocs( filename );
    NUMBER_OF_DOCS = noOfDocs;
    iterate( noOfDocs, 1000 );
    }

    // For testing
    public PageRankSparse() {
            int noOfDocs = readDocs("links5.txt");
            NUMBER_OF_DOCS = noOfDocs;
    }


    /* --------------------------------------------- */


    /**
     *   Reads the documents and fills the data structures. 
     *
     *   @return the number of documents read.
     */
    int readDocs( String filename ) {
        int fileIndex = 0;
        System.out.println("reading...");
    }

    public static void main( String[] args ) {
    if ( args.length != 1 ) {
        System.err.println( "Please give the name of the link file" );
    }
    else {
        new PageRankSparse( args[0] );
    }
    }
}

The output:

reading...
reading...
NUMBER_OF_DOCS: 0

As you can see, readDocs has been executed twice. This leads to unintended behaviour.

How can I make sure readDocs is only executed one time? I've tried this (removing readDocs() call from subclass constructor):

public class PageRankMonteCarlo extends PageRankSparse {


    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Please provide a filename");
        }
        new PageRankMonteCarlo(args[0]);
    }

    public PageRankMonteCarlo(String filename) {
        System.out.printf("NUMBER_OF_DOCS: %d\n", NUMBER_OF_DOCS);
    }
}

But there are two problems:

  1. It feels weird to pass String filename to subclass constructor when it doesn't even use it.
  2. The wrong superclass constructor is called. I want PageRankMonteCarlo(String filename) to be executed. Instead, PageRankMonteCarlo() is executed.

How can I get the behaviour I want?

Upvotes: 0

Views: 45

Answers (1)

Sean Van Gorder
Sean Van Gorder

Reputation: 3453

Just pass the filename to the superclass constructor. If it's something the superclass also needs to do, it should be handled in the superclass.

public PageRankMonteCarlo(String filename) {
    super(filename);
    System.out.printf("NUMBER_OF_DOCS: %d\n", NUMBER_OF_DOCS);
}

If you need to avoid doing something that the superclass constructor does (like the iterate call), you could make it conditional with another parameter:

public PageRankSparse( String filename, boolean doIterate ) {
    int noOfDocs = readDocs( filename );
    NUMBER_OF_DOCS = noOfDocs;
    if (doIterate) {
        iterate( noOfDocs, 1000 );
    }
}

and have the subclass call super(filename, false);.

Also, I would recommend removing that "for testing" no-arg constructor, which is what the subclass constructor is calling now (all constructors will automatically call super() unless a super call is specified). You can test the class by calling the normal constructor with "links5.txt".

Upvotes: 1

Related Questions