THE SYLLABUS TASK
What you need to build
Write a Java program for a vehicle rental company using hierarchical inheritance.
Full syllabus requirements: classes, fields and methods
One integer: rental days (1–365). Driver creates a Car, Bike and SUV. Daily formulas: Car base+200 if AC; Bike base+50 if geared; SUV base+500 if 4WD+100×luxury level.
UNDERSTAND THE IDEA
Explanation
Car, Bike and SUV each extend Vehicle, so the inheritance is hierarchical. Shared vehicle fields stay in the base class, while subclass fields describe each rental type.
A Vehicle reference invokes the overridden calculateFare belonging to the actual subclass. The driver uses three fixed demonstration vehicles and stores the selected days for displayBill. Fare formulas are published assumptions because the syllabus gives no tariff.
TURN THE IDEA INTO STEPS
Step-by-step algorithm
- Validate the rental days.
- Construct three subclass objects through Vehicle references.
- Invoke each overridden calculateFare.
- Store the bill’s day count.
- Display the vehicle identity and corresponding fare.
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.
Vehicle fare 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 Vehicle {
final String vehicleNo, brand;
final double baseFare;
int billedDays;
Vehicle(String no, String brand, double fare) { vehicleNo=no; this.brand=brand; baseFare=fare; }
abstract double calculateFare(int days);
void displayBill() { System.out.println(getClass().getSimpleName()+" | "+vehicleNo+" | "+brand+" | days "+billedDays); money("Fare",calculateFare(billedDays)); }
void validateDays(int days) { if (days<1 || days>365) throw new IllegalArgumentException("Days must be 1–365."); billedDays=days; }
}
static class Car extends Vehicle {
final int noOfSeats; final boolean acAvailable;
Car(String no,String brand,double fare,int seats,boolean ac) { super(no,brand,fare); noOfSeats=seats; acAvailable=ac; }
@Override double calculateFare(int days) { validateDays(days); return days*(baseFare+(acAvailable?200:0)); }
}
static class Bike extends Vehicle {
final boolean helmetRequired, geared;
Bike(String no,String brand,double fare,boolean helmet,boolean geared) { super(no,brand,fare); helmetRequired=helmet; this.geared=geared; }
@Override double calculateFare(int days) { validateDays(days); return days*(baseFare+(geared?50:0)); }
}
static class SUV extends Vehicle {
final boolean fourWheelDrive; final int luxuryLevel;
SUV(String no,String brand,double fare,boolean drive,int luxury) { super(no,brand,fare); fourWheelDrive=drive; luxuryLevel=luxury; }
@Override double calculateFare(int days) { validateDays(days); return days*(baseFare+(fourWheelDrive?500:0)+luxuryLevel*100); }
}
// Rental days. Three sample vehicles make the overriding behavior visible.
public static void main(String[] args) {
try {
int days=integer(1,365);
Vehicle[] vehicles={new Car("CAR01","Maruti",1000,5,true),new Bike("BIKE01","Honda",300,true,true),new SUV("SUV01","Mahindra",2000,true,2)};
for (Vehicle vehicle:vehicles) { vehicle.calculateFare(days); vehicle.displayBill(); }
} 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–27Define the shared vehicle state and abstract fare operation
static abstract class Vehicle {
final String vehicleNo, brand;
final double baseFare;
int billedDays;
Vehicle(String no, String brand, double fare) { vehicleNo=no; this.brand=brand; baseFare=fare; }
abstract double calculateFare(int days);Vehicle stores number, brand, base fare and billed days. Its constructor initialises the common fields. Concrete vehicles must implement calculateFare(int days).
Lines 28–30Reuse bill display and validate rental duration
void displayBill() { System.out.println(getClass().getSimpleName()+" | "+vehicleNo+" | "+brand+" | days "+billedDays); money("Fare",calculateFare(billedDays)); }
void validateDays(int days) { if (days<1 || days>365) throw new IllegalArgumentException("Days must be 1–365."); billedDays=days; }
}displayBill prints identity and calculates for stored billedDays. validateDays accepts 1–365 and remembers the accepted duration. Each concrete fare method calls it before calculating.
Lines 31–35Calculate a car’s fare using its AC option
static class Car extends Vehicle {
final int noOfSeats; final boolean acAvailable;
Car(String no,String brand,double fare,int seats,boolean ac) { super(no,brand,fare); noOfSeats=seats; acAvailable=ac; }
@Override double calculateFare(int days) { validateDays(days); return days*(baseFare+(acAvailable?200:0)); }
}The Car constructor delegates common fields with super and stores seat/AC information. The override charges days times base fare plus a daily 200 AC surcharge when enabled.
Lines 36–40Calculate a bike’s fare using its geared option
static class Bike extends Vehicle {
final boolean helmetRequired, geared;
Bike(String no,String brand,double fare,boolean helmet,boolean geared) { super(no,brand,fare); helmetRequired=helmet; this.geared=geared; }
@Override double calculateFare(int days) { validateDays(days); return days*(baseFare+(geared?50:0)); }
}Bike records helmetRequired and geared. Its fare override adds a daily 50 only for geared; the stored helmet flag does not add another charge in this implementation.
Lines 41–45Calculate the SUV-specific daily surcharge
static class SUV extends Vehicle {
final boolean fourWheelDrive; final int luxuryLevel;
SUV(String no,String brand,double fare,boolean drive,int luxury) { super(no,brand,fare); fourWheelDrive=drive; luxuryLevel=luxury; }
@Override double calculateFare(int days) { validateDays(days); return days*(baseFare+(fourWheelDrive?500:0)+luxuryLevel*100); }
}SUV stores four-wheel-drive and luxury level. The override adds 500 per day for four-wheel drive and 100 per luxury level per day before multiplying by days.
Lines 46–51Demonstrate runtime dispatch with three vehicle objects
// Rental days. Three sample vehicles make the overriding behavior visible.
public static void main(String[] args) {
try {
int days=integer(1,365);
Vehicle[] vehicles={new Car("CAR01","Maruti",1000,5,true),new Bike("BIKE01","Honda",300,true,true),new SUV("SUV01","Mahindra",2000,true,2)};
for (Vehicle vehicle:vehicles) { vehicle.calculateFare(days); vehicle.displayBill(); }Read the duration, construct fixed car/bike/SUV examples and iterate through Vehicle references. The first calculateFare call validates and stores days; displayBill calls the override again for the same duration without adding a cumulative charge.
Lines 52–54Report 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
- For two days, the AC Car costs 2×(1000+200) = 2400.
- The geared Bike costs 2×(300+50) = 700.
- The 4WD luxury-level-2 SUV costs 2×(2000+500+200) = 5400.
- The same base-reference method call chooses three different calculations.
CHECK THE BEHAVIOUR
Sample input & output
These outputs were captured by running the exact delivered Java project.
Sample 1
2
Car | CAR01 | Maruti | days 2
Fare: 2400.00
Bike | BIKE01 | Honda | days 2
Fare: 700.00
SUV | SUV01 | Mahindra | days 2
Fare: 5400.00
Sample 2
1
Car | CAR01 | Maruti | days 1
Fare: 1200.00
Bike | BIKE01 | Honda | days 1
Fare: 350.00
SUV | SUV01 | Mahindra | days 1
Fare: 2700.00
Common mistakes
- Overriding must keep the compatible method signature.
- Use super(...) to initialize inherited fields.
- Do not mistake this hierarchy for multilevel inheritance.
WHY THIS GROWTH RATE?
Time and space complexity
O(v) fixed-size fare calculations for v vehicles; O(1) per vehicle, plus printed text.
Each subclass formula uses a constant number of numeric fields. Iterating through v references is therefore O(v), with no loop over individual rental days.
Each object has fixed field storage. Runtime dispatch selects a method but does not add an input-size-dependent scan.
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 is this vehicle design hierarchical inheritance?
Car, Bike and SUV all directly extend the same Vehicle class. They are sibling subclasses rather than a chain of descendants.
How is calculateFare selected through a Vehicle reference?
The actual runtime object determines the overridden method. A reference holding a Car calls Car’s implementation even though its declared type is Vehicle.
What does super(...) initialize in a vehicle constructor?
It calls the Vehicle constructor to fill vehicle number, brand and base fare before the subclass initializes its own fields.
Why is Vehicle abstract in this example?
A generic vehicle has no single specified fare formula. Declaring calculateFare abstract requires each concrete rental type to provide its own calculation.
Does calculating fare loop once for every rental day?
No. The implementation multiplies the daily rate by days. Its arithmetic operation count is fixed regardless of the accepted day value.
Do all subclass attributes have to affect the demonstration tariff?
No. Attributes such as seat count or helmet requirement still describe the vehicle, while the published tariff uses selected relevant fields. Different business rules could incorporate more fields.