Polymorphism for Batch Processing in Salesforce

To consolidate your code, set up an abstract class:

public abstract class BaseJob implements Database.Batchable<SObject>, Database.Stateful {
    String query;
    public void setQuery(String query) {
        this.query = query;
    }
    public Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator(query);
    }
    public abstract void execute(Database.BatchableContext context, SObject[] scope);
    public abstract void finish(Database.BatchableContext context);
}

Now, we can implement your JobX classes:

public class Job1 extends BaseJob {
    public override void execute(Database.BatchableContext context, SObject[] scope) {
        // Do whatever we need to do
    }
    public override void finish(Database.BatchableContext context) {
        // And finish up
    }
}

Finally, we just need to call your job:

BaseJob j = new Job1();
j.setQuery('select id from lead');
Database.executeBatch(j);

Or dynamically:

public static void doJob(Type className, String withQuery) {
    BaseJob j = (BaseJob)className.newInstance();
    j.setQuery(withQuery);
    Database.executeBatch(j);
}

There is an Object Oriented Programming concept.

If user has defined a constructor in a class. The default constructor doesn't work or can be called. If user defined constructor signature is same as default constructor. User defined constructor will override the default constructor.

So, you have defined a constructor:-

global Job1(String query) 
{
        this.query = query;
}

It takes argument type String. Because of this no argument constructor (default constructor) is removed from class definition.

If you want to use new Job(), define the constructor as below but make sure query need to be set:

global Job1() 
{
     // TO DO
}

For completeness, note that inheritance isn't always the best approach. Where you have common behaviour (methods), classes that support those methods can be identified via an interface:

global interface QueryConfigurable { 
    void setQuery(String query;
}

like this:

global class Job1 implements QueryConfigurable, ... {
    ...
}

Would result in a cast for this example, but in other cases could be a bit cleaner:

Job1 j = new Job1();
((QueryConfigurable) j).setQuery('select id from lead');
Database.executeBatch(j);

With this approach you can compose functionality using multiple small interfaces; inheritance is an all or nothing approach.