Explore Abstract Class and Method in Java: Learn Rules to Streamline Your Code
Updated on Mar 06, 2025 | 23 min read | 79.5k views
Share:
For working professionals
For fresh graduates
More
Updated on Mar 06, 2025 | 23 min read | 79.5k views
Share:
Table of Contents
Have you ever worked with classes in Java that share some methods but differ in specific ways? Abstract classes and methods in Java can solve that problem. They let you define common features in one place while giving child classes the freedom to fill in specific details. That approach keeps your code organized and encourages reuse.
In this blog, you’ll learn how to declare abstract classes, write abstract methods, and apply their rules in practice. You’ll also explore code examples that show real-life uses, so you can adopt these concepts with confidence. Let’s begin!
Java’s object-oriented design relies on categorizing similar functionality into distinct layers. Abstract classes and methods strengthen that design by helping you define shared fields and behavior while leaving certain implementation details for child classes.
This approach lets you avoid duplicating the same setup in every subclass and keeps your code consistent across different parts of your application. It also simplifies maintenance because any shared functionality resides in a single location rather than being scattered throughout many files.
Ready to see how these ideas turn into practical definitions and code? Let’s break them down.
An abstract class is a class declared with the abstract keyword and cannot be instantiated. It outlines a set of behaviors and properties that subclasses must adopt or customize.
Please note: To instantiate a class means to create an actual object from it using the new keyword, which you cannot do for an abstract class in Java.
Below are the key facts that define an abstract class in Java:
Here’s an example that demonstrates how an abstract class can unify common data and methods while requiring each subclass to fill in its own specifics:
abstract class Shape {
String color;
// Abstract method: no body here
abstract void draw();
// Concrete method: has a body
void setColor(String color) {
this.color = color;
}
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a circle in color: " + color);
}
}
Output:
Drawing a circle in color: Red
What’s happening in the code?
An abstract method is declared with the abstract keyword but provides no implementation. It serves as a contract that subclasses must fulfill rather than a fully defined function.
Here are the core points to note about abstract methods in Java:
Here’s a concise code snippet demonstrating how an abstract method forces a subclass to provide its own implementation:
abstract class Animal {
// Abstract method
abstract void makeSound();
// Concrete method
void sleep() {
System.out.println("Sleeping...");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark!");
}
}
Output (assuming the main method does this):
Bark!
Sleeping...
What’s happening in the code?
Also Read: Keywords in Java: List of All Top Java Keywords
If you’re an absolute beginner, you will greatly benefit from upGrad’s free tutorial, Introduction to Java Tutorial. Learn all Java concepts from beginner to advanced now!
Abstract classes and methods in Java let you group related logic into a single blueprint so child classes do not start from zero. They define shared behavior in one place while allowing each subclass to fill in specific details. This keeps your code consistent across different classes that share common traits.
Let’s now see the main reasons to rely on abstract classes and methods in Java:
Also Read: The Root Class from Which All Java Classes Got Inherited
An abstract class holds core details you want all related subclasses to inherit, yet it also sets aside certain methods that those subclasses must implement on their own. You can include fields, constructors, and even non-abstract methods in an abstract class, which allows you to avoid redundant code across different child classes.
You decide which parts remain optional for subclasses and which parts they must redefine.
Let's first review the formal rules, then explore how to handle instantiation, followed by multiple code examples.
Rules for Abstract Classes in Java
Also Read: Parameterized Constructors in Java
To declare an abstract class, add the abstract keyword before the class keyword. For instance:
abstract class Shape {
// Shared fields
String color;
// Abstract methods (no body)
abstract void draw();
// Concrete methods (with a body)
void setColor(String color) {
this.color = color;
}
}
From here, you extend Shape in a concrete class like Circle or Rectangle to provide an actual draw() method.
You cannot instantiate an abstract class by writing something like new AbstractExample(). That line triggers a compile-time error because an abstract class is incomplete by design.
Instead, here’s what you can do:
For instance, if you have an abstract class Vehicle { abstract void startEngine(); }, you cannot do new Vehicle().
Instead, you might write:
class Car extends Vehicle {
@Override
void startEngine() {
System.out.println("Car engine started!");
}
}
// Then in some main method:
Vehicle vehicle = new Car(); // Allowed, but vehicle itself is an abstract reference
In this way, Car does the real work, while Vehicle just defines the structure.
Also Read: Errors and Debugging in Java
Below are several examples showcasing different structures and uses of abstract classes.
Example 1: Basic Abstract Class with Abstract and Concrete Methods
What’s happening in the code snippet? You define an abstract class Device with both an abstract method and a concrete method. The subclass Mobile implements the abstract method.
abstract class Device {
abstract void powerOn(); // Abstract method
void info() { // Concrete method
System.out.println("General device information...");
}
}
class Mobile extends Device {
@Override
void powerOn() {
System.out.println("Powering on the mobile device.");
}
}
public class ExampleOne {
public static void main(String[] args) {
Device d = new Mobile();
d.powerOn();
d.info();
}
}
Output:
Powering on the mobile device.
General device information...
Explanation:
Example 2: Abstract Class with a Constructor
What’s happening in the code snippet? An abstract class Building sets a common property in its constructor, which the subclass House inherits.
abstract class Building {
String address;
Building(String address) {
this.address = address;
System.out.println("Abstract Building constructor called.");
}
abstract void openDoor();
}
class House extends Building {
House(String address) {
super(address); // Calls the Building constructor
}
@Override
void openDoor() {
System.out.println("Opening house door at " + address);
}
}
public class ExampleTwo {
public static void main(String[] args) {
House house = new House("123 Maple Street");
house.openDoor();
}
}
Output:
Abstract Building constructor called.
Opening house door at 123 Maple Street
Explanation:
Also Read: Constructors in Java: A Comprehensive Guide
Example 3: Abstract Class with Static Method
What’s happening in the code snippet? You define an abstract class that has a static method you can call without an instance.
abstract class Calculator {
static int add(int a, int b) {
return a + b;
}
abstract int multiply(int a, int b);
}
class SimpleCalc extends Calculator {
@Override
int multiply(int a, int b) {
return a * b;
}
}
public class ExampleThree {
public static void main(String[] args) {
int sum = Calculator.add(5, 10);
System.out.println("Sum: " + sum);
SimpleCalc calc = new SimpleCalc();
System.out.println("Multiplication: " + calc.multiply(4, 7));
}
}
Output:
Sum: 15
Multiplication: 28
Explanation:
Also Read: Exploring Static Method in Java: A Comprehensive Guide
Example 4: Abstract Class with a Final Method
What’s happening in the code snippet? In this snippet, you create a final method in the abstract class so subclasses cannot override it.
abstract class Printer {
final void printHeader() {
System.out.println("=== Header ===");
}
abstract void printContent();
}
class TextPrinter extends Printer {
@Override
void printContent() {
System.out.println("Plain text content here.");
}
}
public class ExampleFour {
public static void main(String[] args) {
TextPrinter tp = new TextPrinter();
tp.printHeader();
tp.printContent();
}
}
Output:
=== Header ===
Plain text content here.
Explanation:
Example 5: Abstract Class without Abstract Methods
What’s happening in the code snippet? Here, you declare a class as abstract even though it lacks an abstract method. This approach is sometimes used to prevent direct instantiation while sharing certain code.
abstract class VehicleBase {
void showType() {
System.out.println("Generic vehicle.");
}
}
class Bike extends VehicleBase {
void ride() {
System.out.println("Riding the bike.");
}
}
public class ExampleFive {
public static void main(String[] args) {
// VehicleBase vb = new VehicleBase(); // Not allowed
Bike b = new Bike();
b.showType();
b.ride();
}
}
Output:
Generic vehicle.
Riding the bike.
Explanation:
Example 6: Abstract Class with a Main Method
What’s happening in the code snippet? Even though you cannot instantiate an abstract class, you can still include a main() method inside it. That method can create instances of a subclass.
abstract class AnimalBase {
abstract void makeSound();
public static void main(String[] args) {
System.out.println("Inside abstract class main");
AnimalBase animal = new DogConcrete();
animal.makeSound();
}
}
class DogConcrete extends AnimalBase {
@Override
void makeSound() {
System.out.println("Woof!");
}
}
Output:
Inside abstract class main
Woof!
Explanation:
These examples cover many possibilities, from constructors and static methods to final methods and no abstract methods. By mixing these approaches, you can craft abstract classes that effectively share code, enforce rules, and remain flexible for future needs.
Abstract methods let you define actions without revealing exactly how they happen. Think of them as a contract that forces each subclass to say, “Yes, I will provide my own version of this method.” The parent class remains silent on the details, leaving room for every child class to adapt that method to its own needs.
Below are the core principles of abstract methods and how to implement them in code.
Here are the rules for abstract methods which you must understand.
1. Declaration
Use the keyword abstract, then specify the return type and name, ending with a semicolon instead of braces.
Here’s an example:
abstract void doSomething(); // No method body
2. No Body
An abstract method cannot have a method body. If you write { }, you create a compile-time error.
3. Mandatory Override
Any concrete subclass must override all inherited abstract methods. If it does not, that subclass must also be declared abstract.
Here’s an example:
// If a subclass fails to provide an override,
// declare it abstract too.
4. Invalid Modifiers
Combinations like final abstract, static abstract, or private abstract lead to compile-time errors because they conflict with the idea of a method that must be overridden.
Let’s understand abstract methods in Java through some examples now.
Example 1: A Simple Abstract Method That Subclasses Must Override
What’s happening in the code snippet? An abstract class Transport defines a single abstract method move(). One subclass Car implements this method. Another subclass Hovercraft forgets to implement move(), which forces that subclass to become abstract too.
abstract class Transport {
abstract void move(); // Must be overridden by non-abstract subclasses
}
class Car extends Transport {
@Override
void move() {
System.out.println("Car moves on roads.");
}
}
// No move() override here, so this class remains abstract
abstract class Hovercraft extends Transport {
// We'll keep it abstract to avoid implementing move()
}
public class ExampleOne {
public static void main(String[] args) {
Car car = new Car();
car.move();
// Hovercraft hover = new Hovercraft(); // Not allowed, it's abstract
}
}
Output:
Car moves on roads.
Explanation:
Example 2: Demonstrating a Compile Error with Invalid Modifiers
What’s happening in the code snippet? Here, we try to declare final and abstract at the same time. This snippet won’t compile, showing that certain modifiers cannot pair with abstract.
abstract class Appliance {
// Illegal combination of modifiers:
// final abstract void powerOn();
// Correct abstract method:
abstract void powerOn();
}
Output (compilation error):
error: illegal combination of modifiers: abstract and final
Explanation:
Example 3: Different Return Types and Access Levels (Allowed Combinations)
What’s happening in the code snippet? An abstract method can specify various return types and access levels (public or protected, or default if omitted), but it cannot be private.
abstract class Animal {
public abstract String makeSound();
protected abstract int getAge();
}
class Dog extends Animal {
@Override
public String makeSound() {
return "Bark!";
}
@Override
protected int getAge() {
return 5;
}
}
public class ExampleThree {
public static void main(String[] args) {
Dog dog = new Dog();
System.out.println(dog.makeSound());
System.out.println("Dog age: " + dog.getAge());
}
}
Output:
Bark!
Dog age: 5
Explanation:
Following these guidelines ensures that abstract methods remain a clear contract for subclasses to fulfill, without any conflicts from incompatible modifiers or missing implementations.
An abstract class is a special kind of class that can hold both completed and unfinished methods, while an abstract method is simply a method without a body. One focuses on structuring multiple behaviors at once; the other highlights a single behavior that subclasses must implement on their own.
Let’s line up all the differences in a clear table.
Aspect |
Abstract Class |
Abstract Method |
Definition | A class marked with abstract, which cannot be instantiated and may contain a mix of abstract and concrete methods. | A method declared with abstract, providing no body and requiring subclasses to supply an implementation. |
Location | Declared at the class level (e.g., abstract class MyClass {...}). | Found inside an abstract class or an interface (e.g., abstract void myMethod();). |
Purpose | Provides a blueprint for multiple related subclasses, sharing common fields and methods while leaving certain methods unfinished. | Enforces a contract for a specific behavior, making it mandatory for concrete subclasses to define that method’s logic. |
Instantiation | You cannot do new AbstractClass(). You must instantiate a concrete subclass instead. | An abstract method cannot exist independently. It’s part of an abstract class or interface that cannot be instantiated on its own. |
Implementation | Can include both abstract and non-abstract (concrete) methods, along with fields, constructors, and more. | Must be implemented (overridden) in any non-abstract subclass; otherwise, that subclass is also abstract. |
Inheritance | Subclasses inherit both the abstract and concrete methods, plus any fields or constructors. | Each abstract method must be overridden if the subclass is concrete, or left unimplemented if the subclass is abstract. |
Usage | Ideal when you want to share code among related classes, including partial implementations. | Suited for declaring a method signature that forces subclasses to provide their own version of its body. |
Modifiers | Allows static methods, final methods, and instance variables of any access level. | Cannot be final, static, or private because it defeats the purpose of future overrides. |
To clear the air once and for all: yes, a class can be abstract without any abstract methods.
You might mark a class as abstract simply because you want to prevent anyone from creating objects of that class. Even if all of its methods are fully implemented, declaring the class abstract signals that it is only meant to be extended by other classes.
This practice also helps you group certain methods and fields together without allowing direct instantiation.
Let’s see some possible reasons why developers do this:
Subclasses extend an abstract class to inherit common fields and methods while adding or refining specific behaviors. Every abstract method within the parent must either be implemented by the subclass or remain unimplemented if the subclass itself is declared abstract. This arrangement ensures that the entire class hierarchy eventually provides the necessary functionality.
Let’s lay out the main steps involved in using abstract classes and methods in subclasses:
Let’s understand this better with the help of an example.
This code snippet shows how a subclass Dog inherits from an abstract class Animal, overriding the abstract method makeSound() to supply its own logic.
abstract class Animal {
abstract void makeSound();
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog();
myAnimal.makeSound();
}
}
Output:
Bark
Explanation:
You can assign a Dog object to an Animal reference, then call makeSound().
Even though you cannot call new on an abstract class, you can still hold a reference to it. This approach allows you to benefit from polymorphism, where a single parent-type reference can point to different subclass objects. When you call methods on that reference, Java decides which subclass method to invoke at runtime, making your code more flexible.
Let’s see the key points about abstract class references:
Example: Demonstrating Abstract Class References
What’s happening? In this example, Vehicle is abstract, but you can have a Vehicle reference point to different subclasses like Car or Bike. Each subclass overrides startEngine() differently.
abstract class Vehicle {
abstract void startEngine();
}
class Car extends Vehicle {
@Override
void startEngine() {
System.out.println("Car engine starting with a key!");
}
}
class Bike extends Vehicle {
@Override
void startEngine() {
System.out.println("Bike engine starting with a kick!");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myVehicle = new Car();
myVehicle.startEngine();
myVehicle = new Bike();
myVehicle.startEngine();
}
}
Output:
Car engine starting with a key!
Bike engine starting with a kick!
Explanation:
Abstraction is a core principle in object-oriented programming that hides internal complexity while revealing only essential functionality. It allows you to define interfaces and class structures without exposing every detail of how things actually work under the hood. Instead, you focus on what should be done, leaving the how to specific classes or methods.
By separating the conceptual framework from the underlying implementation, abstraction helps you maintain cleaner code, simplify debugging, and adapt easily to new requirements. It also lets you layer functionality in a way that is easy for others to understand and extend.
Here are the two types:
Now, let’s have a look at how these two differ across different aspects.
Aspect |
Partial Abstraction (Abstract Classes) |
Full Abstraction (Interfaces) |
Instantiation | Cannot be instantiated directly, but can have a constructor called by subclasses. | Cannot be instantiated, and no constructors allowed. |
Method Types | Can contain both abstract and concrete (implemented) methods. | Typically all abstract methods, though default and static methods are allowed in modern Java. |
Fields | Can declare instance variables (not necessarily final). | All fields are implicitly public static final. |
Inheritance | A class can extend only one abstract class. | A class can implement multiple interfaces. |
Use Case | Ideal for partial code sharing among related classes that need some common logic. | Useful for specifying a contract or behavior across possibly unrelated classes. |
Polymorphism in Java enables you to handle different object types through the same reference. An abstract class lays down a common structure, and each subclass overrides the abstract methods with its own unique approach.
This setup allows you to call the same method name on different subclasses and get distinct results, all while using a single reference type.
Here are the key points you should know:
Example: One Parent Reference, Multiple Subclass Behaviors
What’s happening in the code snippet?Animal is abstract with the method makeSound(). Two subclasses — Dog and Cat — override it. We assign different subclass objects to the same Animal reference, and each one runs its own method implementation.
abstract class Animal {
abstract void makeSound();
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Woof!");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow!");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog();
myAnimal.makeSound(); // Dog's version
myAnimal = new Cat();
myAnimal.makeSound(); // Cat's version
}
}
Output:
Woof!
Meow!
Explanation:
Also Read: Difference Between Overloading and Overriding in Java
Mistakes with abstract classes in Java and methods can lead to inefficient code. Below are common pitfalls:
Abstract classes in Java work best when used with clear strategies. Here are practical approaches to make the most of them.
Practice | Description |
Keep Focused | Define only relevant abstract and concrete methods. |
Avoid Overuse | Use abstraction where genuinely needed. |
Use Constructors Wisely | Share common initialization logic in abstract classes. |
Document Abstract Methods | Clarify expected behavior in comments. |
Favor Interfaces | Use interfaces for unrelated behaviors. |
Leverage Polymorphism | Use abstract classes for base-type polymorphism. |
You may not need an abstract class for every scenario, but certain situations call for a common parent class that enforces specific behaviors while leaving room for subclasses to customize the details. This approach balances consistency and flexibility so your code remains both unified and adaptable.
Here are some instances when using abstract class and abstract method in Java makes most sense:
Advance your Java programming journey with upGrad. upGrad offers clarity and practical learning opportunities to strengthen your skills. Here are upGrad's Core Java Courses you should explore.
Take the first step toward achieving your career goals with upGrad’s personalized counseling services. Visit upGrad's offline centers for expert guidance tailored to your needs.
Related Blogs:
Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.
Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.
Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.
Get Free Consultation
By submitting, I accept the T&C and
Privacy Policy
India’s #1 Tech University
Executive PG Certification in AI-Powered Full Stack Development
77%
seats filled
Top Resources