1

Say I want to solve a bunch of Project Euler problems in Java, and rather than give each problem class the boilerplate of its own main method, inherit it and have a "solve" method instead.

Is there a way of getting the problem class's name to print out along with the solution?

What I have:

abstract class Problem {

    private static String problemName = ???

    public static void main(String[] args) {
//  If I could summon an instance of the sub-class then it would be easy
//        Problem p = new ... what?
        System.out.println(problemName + ": " + solve());
    }

    abstract static long solve();
// oops, you can't do abstract static in Java :(
}

then

public class Euler_001 extends Problem {
    static long solve() {...}
}

The problem is that the various hacks to get the class name given in this answer return "Problem", not "Euler_001".

I guess I have to instantiate the problem class, but then how do I do that?

Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180

2 Answers2

1

The static context does not help inheritance where the parent needs to call the child. Use instances with abstraction:

abstract class Problem {

    public static void main(String[] args) throws Exception {

        Problem problem;

        //Now, depending on where the exact problem is specified:

        //Class known at compile time
        problem = new Euler_001();

        //Class passed as parameter
        problem = (Problem) Class.forName(args[0]).getConstructor().newInstance();

        System.out.println(problem.getProblemName() + ": " + problem.solve());
    }

    abstract long solve();
    abstract String getProblemName();
}

And the subclass will provide a normal implementation that overrides abstract methods:

class Euler_001 extends Problem {
    @Override
    long solve() {
         return 0;
     }

    @Override
    String getProblemName() {
        return "????";
    }
}

Depending on your configuration approach, you can create an instance of the concrete class based on the class name, inside the parent's main method.

This way, the Problem class can be called with:

java com.mypackage.Problem "com.mypackage.Euler_001"
ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • If I am understanding correctly, the OP asked for the constructor that is tagged as "Class passed as parameter". If so, the line tagged as "Class known at compile time" could be removed. – Egl Sep 21 '18 at 11:57
  • Really I just wanted to right-click and select Run in IntelliJ without adding extra boilerplate, but if I have to do it by putting the problem name into the run configuration I guess that is not too arduous (though not great if this were a more complex application with potential refactoring). I was more curious about if it "could be done" in some clean and easy way. Thanks – Luigi Plinge Sep 21 '18 at 12:11
  • @LuigiPlinge If you want to be able to just run a particular problem, then the better approach would be to reverse the link: have `main` in `Euler_001` or other subclasses. But with that, inheritance becomes useless as there is nothing to reuse from the parent – ernest_k Sep 21 '18 at 12:15
0

Static variables and methods can not be overriden - they get replaced. So, as per my understanding we need to create instance of sub-class.
I checked -
Problem p = new Euler_001();
System.out.println(p.getClass().getSimpleName()); //prints Euler_001

Haripriya
  • 822
  • 1
  • 14
  • 27