THE SYLLABUS TASK
What you need to build
Create a payroll system using inheritance & method overriding.
Full syllabus requirements: classes, fields and methods
Three lines: manager, developer and intern days present (0–30). Monthly assumptions: manager base 50000+bonus 10000; developer base 40000+allowance 5000; intern stipend 10000. Net pay is monthly amount×days/30.
UNDERSTAND THE IDEA
Explanation
The Employee base class shares identity, attendance and pay-slip behavior. Manager, Developer and Intern override calculateSalary while remaining usable through Employee references.
The 30-day proration rule applies to each subclass’s monthly amount. displayPaySlip reads the attendance and invokes the subclass salary calculation, making runtime dispatch visible without separate type checks.
TURN THE IDEA INTO STEPS
Step-by-step algorithm
- Read the three attendance values.
- Construct the three employee subclasses.
- Calculate each monthly pay basis in its overridden method.
- Prorate by daysPresent/30.0.
- Print each employee’s type, days and net salary.
SEE THE CORE OPERATION
Flowchart
This chart focuses on the named operation or core OOP decision. Diamonds show conditions; labeled branches show outcomes. Read it with the complete algorithm and source for input handling and other operations. Scroll within the diagram on a phone.
Payroll salary dispatch
Main.java
import java.util.*;
public class Main {
private static final Scanner IN = new Scanner(System.in).useLocale(Locale.ROOT);
static String text() {
if (!IN.hasNextLine()) throw new IllegalArgumentException("Incomplete input.");
String value = IN.nextLine().trim();
if (value.isEmpty() || value.length() > 200) throw new IllegalArgumentException("Text must have 1–200 characters.");
return value;
}
static int integer(int low, int high) {
int value = Integer.parseInt(text());
if (value < low || value > high) throw new IllegalArgumentException("Integer out of range.");
return value;
}
static double number(double low, double high) {
double value = Double.parseDouble(text());
if (!Double.isFinite(value) || value < low || value > high) throw new IllegalArgumentException("Number out of range.");
return value;
}
static void money(String label, double value) { System.out.printf(Locale.ROOT, "%s: %.2f%n", label, value); }
static abstract class Employee {
final int id, daysPresent; final String name; final double baseSalary;
Employee(int id,String name,double baseSalary,int days) { this.id=id; this.name=name; this.baseSalary=baseSalary; daysPresent=days; }
abstract double calculateSalary();
void displayPaySlip() { System.out.println(getClass().getSimpleName()+" | "+id+" | "+name+" | days "+daysPresent); money("Net salary",calculateSalary()); }
double prorate(double monthly) { return monthly*daysPresent/30.0; }
}
static class Manager extends Employee {
final double bonus;
Manager(int id,String name,double base,int days,double bonus) { super(id,name,base,days); this.bonus=bonus; }
@Override double calculateSalary() { return prorate(baseSalary+bonus); }
}
static class Developer extends Employee {
final double projectAllowance;
Developer(int id,String name,double base,int days,double allowance) { super(id,name,base,days); projectAllowance=allowance; }
@Override double calculateSalary() { return prorate(baseSalary+projectAllowance); }
}
static class Intern extends Employee {
final double stipend;
Intern(int id,String name,int days,double stipend) { super(id,name,0,days); this.stipend=stipend; }
@Override double calculateSalary() { return prorate(stipend); }
}
// Days present for manager, developer, intern (0–30), one per line.
public static void main(String[] args) {
try {
Employee[] team={new Manager(1,"Asha",50000,integer(0,30),10000),new Developer(2,"Ravi",40000,integer(0,30),5000),new Intern(3,"Priya",integer(0,30),10000)};
for (Employee employee:team) employee.displayPaySlip();
} catch (IllegalArgumentException e) { System.out.println("Invalid input: "+e.getMessage()); }
}
}
Copy a source file or download the project to preserve its file names.
USE THE RIGHT ENVIRONMENT
How to compile and run
Install a JDK (Java 11 or newer; JDK 17 is suitable), extract this project’s ZIP into its own folder, then open a terminal in that folder.
javac -encoding UTF-8 Main.java
java MainThe standalone source is named Main.java and its entry class is Main. You may also paste it into an online Java compiler and supply the sample input there. Choose Java explicitly; these pages do not change the site compiler or import code automatically.
Each experiment has its own folder because many use the public class Main. Compile and run one experiment at a time.
UNDERSTAND THE JAVA CODE
Line-by-line explanation
These steps follow the exact Java source above. Related statements are grouped; line numbers count blank lines and restart for each file. Start with main to follow execution, then open the constructors, methods or event handlers it uses.
Main.java
Lines 1–4Import utilities and create the shared input reader
import java.util.*;
public class Main {
private static final Scanner IN = new Scanner(System.in).useLocale(Locale.ROOT);java.util.* imports utility type names such as Scanner, Locale and collections. Main is the public class matching Main.java. The private static final IN field holds one shared Scanner for System.in; final prevents replacing that reference. The scanner uses Locale.ROOT.
Lines 5–10Read one nonempty trimmed input line
static String text() {
if (!IN.hasNextLine()) throw new IllegalArgumentException("Incomplete input.");
String value = IN.nextLine().trim();
if (value.isEmpty() || value.length() > 200) throw new IllegalArgumentException("Text must have 1–200 characters.");
return value;
}text checks whether a line exists, reads it and removes leading/trailing whitespace. Reject empty text and lengths above 200 by throwing IllegalArgumentException. Otherwise return the string. One field is read per line, so these helpers do not mix nextInt with leftover newlines.
Lines 11–15Parse and range-check an integer field
static int integer(int low, int high) {
int value = Integer.parseInt(text());
if (value < low || value > high) throw new IllegalArgumentException("Integer out of range.");
return value;
}Integer.parseInt converts the returned string to int or throws NumberFormatException, a subtype of IllegalArgumentException. Reject values outside the caller’s inclusive low/high limits, then return the accepted integer.
Lines 16–20Parse and range-check a finite decimal field
static double number(double low, double high) {
double value = Double.parseDouble(text());
if (!Double.isFinite(value) || value < low || value > high) throw new IllegalArgumentException("Number out of range.");
return value;
}Double.parseDouble reads the string as a double. Double.isFinite rejects NaN and infinities as well as the explicit low/high range check. Return only a finite accepted value; exceptions transfer control to a matching catch block.
Line 21Format a labelled numeric result consistently
static void money(String label, double value) { System.out.printf(Locale.ROOT, "%s: %.2f%n", label, value); }money is a formatting helper: %s prints the label, %.2f prints two decimal places, and %n ends the line. Locale.ROOT fixes locale-sensitive formatting. The helper can also display non-currency quantities; it does not change the stored value.
Lines 22–25Define a common abstract employee contract
static abstract class Employee {
final int id, daysPresent; final String name; final double baseSalary;
Employee(int id,String name,double baseSalary,int days) { this.id=id; this.name=name; this.baseSalary=baseSalary; daysPresent=days; }
abstract double calculateSalary();Employee stores identity, monthly base and days present. Its constructor initialises those fields, and abstract calculateSalary requires each concrete subtype to supply a salary calculation. The abstract class itself is not directly instantiated.
Lines 26–28Reuse display and attendance proration
void displayPaySlip() { System.out.println(getClass().getSimpleName()+" | "+id+" | "+name+" | days "+daysPresent); money("Net salary",calculateSalary()); }
double prorate(double monthly) { return monthly*daysPresent/30.0; }
}displayPaySlip calls calculateSalary on the actual receiver, enabling runtime dispatch. prorate scales a monthly amount by daysPresent/30.0; the decimal divisor avoids integer division.
Lines 29–33Override salary for a manager
static class Manager extends Employee {
final double bonus;
Manager(int id,String name,double base,int days,double bonus) { super(id,name,base,days); this.bonus=bonus; }
@Override double calculateSalary() { return prorate(baseSalary+bonus); }
}The constructor calls super to initialise inherited fields, then stores bonus. The override prorates base plus bonus. @Override asks the compiler to check that the method really overrides a parent declaration.
Lines 34–38Override salary for a developer
static class Developer extends Employee {
final double projectAllowance;
Developer(int id,String name,double base,int days,double allowance) { super(id,name,base,days); projectAllowance=allowance; }
@Override double calculateSalary() { return prorate(baseSalary+projectAllowance); }
}Store projectAllowance after the parent constructor call. This override prorates base plus that allowance rather than the manager’s bonus.
Lines 39–43Override salary for an intern
static class Intern extends Employee {
final double stipend;
Intern(int id,String name,int days,double stipend) { super(id,name,0,days); this.stipend=stipend; }
@Override double calculateSalary() { return prorate(stipend); }
}An intern supplies zero base to the parent and stores a stipend. Its override prorates only the stipend. All three subtypes honour the same calculateSalary method contract.
Lines 44–48Call different overrides through Employee references
// Days present for manager, developer, intern (0–30), one per line.
public static void main(String[] args) {
try {
Employee[] team={new Manager(1,"Asha",50000,integer(0,30),10000),new Developer(2,"Ravi",40000,integer(0,30),5000),new Intern(3,"Priya",integer(0,30),10000)};
for (Employee employee:team) employee.displayPaySlip();Read 0–30 days for each fixed example employee. The array type is Employee[], but its elements have different concrete classes. Each displayPaySlip call dispatches to that object’s own salary implementation.
Lines 49–51Report invalid input and close the enclosing scopes
} catch (IllegalArgumentException e) { System.out.println("Invalid input: "+e.getMessage()); }
}
}The catch handles IllegalArgumentException, including invalid numeric strings from the helpers, and prints its message. The final braces close main and Main. Java objects become eligible for garbage collection when no live reference needs them; this program does not manually free them.
FOLLOW THE STATE
Dry run
- A manager present 15 days receives 60000×15/30 = 30000.
- A developer present all 30 days receives 45000.
- An intern with zero attendance receives zero.
- displayPaySlip calls the correct overridden calculation for each.
CHECK THE BEHAVIOUR
Sample input & output
These outputs were captured by running the exact delivered Java project.
Sample 1
15
30
0
Manager | 1 | Asha | days 15
Net salary: 30000.00
Developer | 2 | Ravi | days 30
Net salary: 45000.00
Intern | 3 | Priya | days 0
Net salary: 0.00
Sample 2
30
30
30
Manager | 1 | Asha | days 30
Net salary: 60000.00
Developer | 2 | Ravi | days 30
Net salary: 45000.00
Intern | 3 | Priya | days 30
Net salary: 10000.00
Common mistakes
- Use floating-point proration rather than truncating days/30.
- Do not add base pay twice for the intern’s stipend-only rule.
- Publish the attendance rule rather than silently inventing one.
WHY THIS GROWTH RATE?
Time and space complexity
O(e) processing for e employees; O(1) arithmetic per pay slip.
The salary formulas access a fixed number of fields. A loop over e Employee references does e constant-size calculations.
The division uses 30.0 to retain fractions. The program is a tariff/proration demonstration; it does not scan daily attendance records or calculate tax rules.
These bounds describe the implemented data processing. Input/output text length, scheduling, framework rendering and runtime/library internals are identified separately where they matter. Educational limits bound the actual examples.
PREPARE FOR YOUR LAB VIVA
Related viva questions & answers
Try answering aloud, then expand to check your reasoning. Questions focus on this program’s classes, state and behavior.
Why can Employee.displayPaySlip call different salary formulas?
calculateSalary is overridden in each concrete subclass. The inherited display method still dispatches that call using the actual employee object.
Why is the denominator written as 30.0?
It makes proration floating-point. With integer days/30, partial attendance could truncate to zero before multiplication.
How is the intern’s stipend represented without adding a second salary?
Intern passes zero base salary to Employee and calculates from its own stipend. That matches the stated stipend-only demonstration rule.
What extra pay component belongs to a Developer?
projectAllowance is combined with baseSalary before attendance proration. It is distinct from Manager’s bonus field.
Why does the base class hold daysPresent?
Attendance is shared by every employee type and appears in every pay slip. Keeping it in the base avoids duplicating that common field.
Can the proration rule be changed without removing polymorphism?
Yes. The formula or shared prorate method can be updated while subclasses continue to override calculateSalary and the driver still uses Employee references.