Java 超类的构造函数是在我不希望它被输入的情况下输入的

Java 超类的构造函数是在我不希望它被输入的情况下输入的,java,Java,我有一个类PageRankMonteCarlo,它扩展了PageRankSparse。PageRankMonteCarlo有一个在main中调用的构造函数。在构造函数内部,调用PageRankSparse.readDocs,以设置PageRankMonteCarlo对象的一些变量 当我运行PageRankMonteCarlo时,会执行PageRankSparse的构造函数,尽管我不希望它这样做。这导致readDocs被调用两次,因为readDocs在PageRankSparse中也被调用。代码如

我有一个类PageRankMonteCarlo,它扩展了PageRankSparse。PageRankMonteCarlo有一个在main中调用的构造函数。在构造函数内部,调用PageRankSparse.readDocs,以设置PageRankMonteCarlo对象的一些变量

当我运行PageRankMonteCarlo时,会执行PageRankSparse的构造函数,尽管我不希望它这样做。这导致readDocs被调用两次,因为readDocs在PageRankSparse中也被调用。代码如下:

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] );
    }
    }
}
输出:

reading...
reading...
NUMBER_OF_DOCS: 0
如您所见,readDocs已经执行了两次。这会导致意外行为

如何确保readDocs只执行一次?我尝试过从子类构造函数中删除readDocs调用:

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);
    }
}
但有两个问题:

当子类构造函数甚至不使用字符串文件名时,将其传递给子类构造函数感觉很奇怪。 调用了错误的超类构造函数。我希望执行PageRankMonteCarloString文件名。而是执行PageRankMonteCarlo。
如何获得所需的行为?

只需将文件名传递给超类构造函数即可。如果它是超类也需要做的事情,那么它应该在超类中处理

public PageRankMonteCarlo(String filename) {
    super(filename);
    System.out.printf("NUMBER_OF_DOCS: %d\n", NUMBER_OF_DOCS);
}
如果您需要避免做超类构造函数所做的事情,比如迭代调用,您可以使用另一个参数使其有条件:

public PageRankSparse( String filename, boolean doIterate ) {
    int noOfDocs = readDocs( filename );
    NUMBER_OF_DOCS = noOfDocs;
    if (doIterate) {
        iterate( noOfDocs, 1000 );
    }
}
并让子类调用superflename,false


此外,我建议删除用于测试no-arg构造函数的属性,这是子类构造函数现在正在调用的,除非指定了super调用,否则所有构造函数都将自动调用super。您可以通过使用links5.txt调用普通构造函数来测试类。

是的,首先调用超类构造函数。这就是为什么你不应该随便把东西放在构造函数里。从两个构造函数中删除所有内容并使用单独的加载方法加载数据怎么样?但是我需要在超类的构造函数中读取文档,因为超类也可以自己运行。若我并没有在那个里运行它,我需要在超类的主要部分运行它,然后我必须使一切都是静态的……不,你们并没有。您可以调用构造函数,然后调用方法。您不需要让构造函数调用方法。正如您所看到的,它可能会导致问题,因此最好避免。