Principles of Object-Oriented Design (OOD)
Object-Oriented Design (OOD) follows a set of principles that help in creating scalable,
maintainable, and reusable software systems. These principles include:
1. Encapsulation – Bundling data and methods that operate on the data within a
single unit (class).
2. Abstraction – Hiding implementation details and exposing only the necessary
parts of an object.
3. Inheritance – Allowing one class to derive properties and behavior from another,
promoting code reuse.
4. Polymorphism – Enabling multiple classes to be treated as instances of the
same parent class, allowing method overriding and overloading.
5. Separation of Concerns (SoC) – Dividing software into different sections to
reduce complexity and improve manageability.
6. Single Responsibility Principle (SRP) – Each class should have only one reason
to change.
7. Open/Closed Principle (OCP) – Software entities should be open for extension
but closed for modification.
8. Liskov Substitution Principle (LSP) – Subtypes should be replaceable by their
base types without affecting functionality.
9. Interface Segregation Principle (ISP) – Clients should not be forced to depend
on interfaces they don’t use.
10. Dependency Inversion Principle (DIP) – High-level modules should not depend
on low-level modules; both should depend on abstractions.
Programming Paradigms
A programming paradigm is a style or way of programming. The major paradigms
include:
1. Procedural Programming
• Based on functions and procedures.
• Uses a top-down approach.
• Examples: C, Pascal.
2. Object-Oriented Programming (OOP)
• Uses objects and classes to structure code.
• Follows principles like encapsulation, inheritance, and polymorphism.
• Examples: Java, Python, C++.
3. Functional Programming (FP)
• Treats computation as the evaluation of mathematical functions.
• Avoids changing state and mutable data.
• Examples: Haskell, Lisp, Scala.
4. Logic Programming
• Based on formal logic.
• Uses declarative statements rather than procedural commands.
• Examples: Prolog.
5. Event-Driven Programming
• Executes code based on events (user actions, messages, etc.).
• Common in GUI applications.
• Examples: JavaScript, C#.
6. Concurrent Programming
• Focuses on executing multiple tasks in parallel.
• Used in distributed and real-time systems.
• Examples: Java (Threads), Go.
Benefits of OOD
• Code Reusability – Promotes reuse of classes and modules.
• Modularity – Enhances code organization and maintainability.
• Scalability – Facilitates software extension and modification.
• Improved Security – Encapsulation hides sensitive data.
• Ease of Debugging – Structured code makes it easier to test and debug.
• Better Collaboration – Multiple developers can work on different modules
independently.
Applications of OOD
• Software Development – Used in frameworks, libraries, and applications.
• Game Development – Game engines use OOP principles for character
interactions.
• Web Development – Web frameworks like Django (Python) and Spring (Java) use
OOP.
• Mobile App Development – OOP is essential in Android (Java/Kotlin) and iOS
(Swift).
• Database Management Systems (DBMS) – Object-relational mapping (ORM)
tools use OOP.
• AI & Machine Learning – Libraries like TensorFlow and PyTorch are designed
using OOP.
• Enterprise Applications – Large-scale business applications use OOD for
maintainability.
Comparison of Java with C and C++ (Click on the arrow on left to
open)
Feature Java C C++
Paradigm Object-Oriented Procedural Multi-paradigm
(OOP) (imperative) (Procedural + OOP)
Platform Platform- Platform-dependent Platform-dependent
Dependency independent (Runs (Compiled to (Compiled to
on JVM) machine code) machine code)
Compilation & Compiled into Compiled into Compiled into
Execution bytecode, executed machine code machine code
on JVM directly directly
Speed & Slower due to JVM Faster because of Faster than Java but
Performance overhead direct machine may have OOP
code execution overhead
Memory Automatic (Garbage Manual Manual
Management Collection) (malloc/free) (new/delete) and
smart pointers
Pointers No direct pointer Uses pointers Supports pointers
access extensively with better safety
Multiple Inheritance Not supported Not applicable (C is Supported with
(Uses Interfaces) not OOP) virtual functions
Operator Not supported Not supported Supported
Overloading
Exception Handling Built-in (try-catch- Not built-in Built-in (try-catch)
finally)
Threading Support Built-in (Thread No built-in support Requires external
class, Runnable) libraries (pthreads)
Memory Safety More secure, Prone to memory Improved over C but
prevents direct leaks and buffer still needs careful
memory access overflows management
Standard Libraries Rich (Collections, Minimal standard Extensive (STL -
I/O, Networking) library Standard Template
Library)
Use Cases Web apps, mobile System Game development,
apps, enterprise programming, system software
software embedded systems
Syntax Simplicity Easier to learn due Low-level syntax, Complex but more
to abstraction requires in-depth powerful than Java
memory
management
Object-Oriented Fully OOP Not OOP Supports both
Support (everything is an procedural and OOP
object)
Key Takeaways:
- C is best for low-level system programming (OS, embedded systems) due to direct
hardware interaction.
- C++ is a hybrid language, offering both procedural and OOP capabilities, suitable for
game engines, real-time systems, and large-scale software.
- Java is platform-independent, has built-in memory management (Garbage Collection),
and is widely used for web development, mobile applications (Android), and enterprise
applications.
JAVA EVOLUTION AND HISTORY
Read on GFG : https://www.geeksforgeeks.org/the-complete-history-of-java-
programming-language/
Features of Java Language
Java is a popular, high-level programming language known for its platform
independence, security, and robustness. Below are its key features:
1. Simple & Easy to Learn
• Java's syntax is similar to C++ but removes complex features like pointers,
operator overloading, and multiple inheritance.
• Automatic memory management (Garbage Collection) simplifies development.
2. Platform Independent (Write Once, Run Anywhere - WORA)
• Java code is compiled into bytecode, which runs on any system with a Java
Virtual Machine (JVM).
• Unlike C and C++, Java does not depend on the underlying OS or hardware.
3. Object-Oriented Programming (OOP)
• Java follows the OOP paradigm, which enhances modularity, code reusability,
and maintainability.
• Core OOP principles in Java:
o Encapsulation (Data hiding)
o Abstraction (Hiding implementation details)
o Inheritance (Code reuse)
o Polymorphism (Method overloading & overriding)
4. Robust & Secure
• Java eliminates common programming errors by:
o Automatic memory management (no manual allocation/deallocation).
o Strong type checking (reduces runtime errors).
o No direct memory access (prevents buffer overflows).
• Security is enhanced with:
o Java Security Manager (Restricts app permissions).
o Bytecode verification (Prevents malicious code execution).
5. Multithreading Support
• Java supports multithreading, allowing concurrent execution of tasks.
• Built-in support via the Thread class and Runnable interface.
6. High Performance with JIT Compiler
• Java uses a Just-In-Time (JIT) compiler to convert bytecode into native machine
code at runtime, improving execution speed.
• Though not as fast as C/C++, Java achieves near-native performance with JVM
optimizations.
7. Automatic Memory Management (Garbage Collection)
• Java automatically manages memory allocation and deallocation using Garbage
Collector (GC).
• Prevents memory leaks and improves efficiency.
8. Rich Standard Library & APIs
• Java provides a vast set of pre-built libraries for:
o Data structures (Collections Framework)
o Networking (java.net)
o Concurrency (java.util.concurrent)
o File handling (java.io, java.nio)
o Database connectivity (JDBC)
9. Dynamic & Extensible
• Java allows dynamic loading of classes at runtime.
• Supports integration with C/C++ code via Java Native Interface (JNI).
11. Portable
• Java applications can run on any OS without modification.
• JVM handles platform-specific implementations.
12. Open Source & Community Support
• Java is free and open-source, backed by a large developer community.
• Regular updates from Oracle and the OpenJDK project.
JDK in Java
The Java Development Kit (JDK) is a cross-platformed software development
environment that offers a collection of tools and libraries necessary for developing Java-
based software applications and applets. It is a core package used in Java, along with
the JVM (Java Virtual Machine) and the JRE (Java Runtime Environment). if you are only
interested in running Java programs on your machine then you can easily do it using Java
Runtime Environment. However, if you would like to develop a Java-based software
application then along with JRE you may need some additional necessary tools, which
is called JDK
Contents of JDK
The JDK has a private Java Virtual Machine (JVM) and a few other resources necessary
for the development of a Java Application.
JDK contains:
• Java Runtime Environment (JRE),
• An interpreter/loader (Java),
• A compiler (javac),
• An archiver (jar) and many more.
The Java Runtime Environment in JDK is usually called Private Runtime because it is
separated from the regular JRE and has extra content. The Private Runtime in JDK
contains a JVM and all the class libraries present in the production environment, as well
as additional libraries useful to developers, e.g, internationalization libraries and the IDL
libraries.
JRE in Java
Java Runtime Environment (JRE) is an open-access software distribution that has a Java
class library, specific tools, and a separate JVM. In Java, JRE is one of the interrelated
components in the Java Development Kit (JDK). It is the most common environment
available on devices for running Java programs. Java source code is compiled and
converted to Java bytecode. If you want to run this bytecode on any platform, you need
JRE. The JRE loads classes check memory access and get system resources. JRE acts as
a software layer on top of the operating system.
Components of Java JRE
The components of JRE are mentioned below:
• Integration libraries include Java Database Connectivity (JDBC)
• Java Naming, Interface Definition Language (IDL)
• Directory Interface (JNDI)
• Remote Method Invocation Over Internet Inter-Orb Protocol (RMI-IIOP)
• Remote Method Invocation (RMI)
• Scripting
JVM (Java Virtual Machine)
JVM is a runtime environment that executes Java bytecode. It converts compiled Java
programs (bytecode) into machine-specific instructions so they can run on any platform
without modification.
Key Responsibilities of JVM:
1. Loads and Executes Java Bytecode – Translates .class files into native machine
code.
2. Manages Memory – Handles heap and stack memory allocation.
3. Performs Garbage Collection – Automatically removes unused objects.
4. Ensures Security – Runs Java programs inside a secure sandbox.
5. Handles Exceptions – Manages runtime errors using exception handling
mechanisms
JRE (Java Runtime Environment)
JRE is a package that contains everything needed to run Java applications. It includes:
1. JVM – The actual engine that runs Java programs.
2. Java Class Libraries – Essential built-in classes and APIs for Java programs.
3. Supporting Files – Configuration files, properties, and resources required to run
Java applications.
JRE vs JVM:
• JRE = JVM + Java Libraries + Other Necessary Files
• JVM is a part of JRE, but JRE does not include development tools like the
compiler (javac).
1. ClassLoader
The ClassLoader is responsible for loading .class files (Java bytecode) into memory
when a Java program runs.
Key Functions:
• Loading: Reads bytecode (.class files) from disk, network, or JAR files.
• Linking: Verifies and prepares classes before execution.
• Initialization: Assigns values to static variables and runs static blocks.
Types of ClassLoaders in JVM:
• Bootstrap ClassLoader – Loads core Java classes (like java.lang.*).
• Extension ClassLoader – Loads extension libraries (lib/ext).
• Application ClassLoader – Loads classes from the classpath.
• Custom ClassLoaders – User-defined loaders for advanced applications.
2. ByteCode Verifier
The ByteCode Verifier ensures that the loaded Java bytecode is valid and does not
perform unsafe operations.
Key Responsibilities:
• Checks for Security Issues – Prevents illegal memory access or corrupt
bytecode.
• Validates Code Structure – Ensures proper usage of data types, method calls,
and stack operations.
• Prevents Malicious Code Execution – Avoids hacking attempts using modified
bytecode.
If the bytecode fails verification, JVM throws a VerifyError and stops execution.
3. Interpreter
The Interpreter converts Java bytecode into machine code line by line and executes it
immediately.
Key Responsibilities:
• Executes Bytecode Directly – Reads and runs instructions without pre-
compiling.
• Slower Than JIT Compilation – Since it processes one instruction at a time, it's
slower than Just-In-Time (JIT) compilation.
JIT Compiler vs. Interpreter:
• Interpreter: Good for quick startup but slower execution.
• JIT Compiler: Compiles frequently used bytecode into native code for faster
execution
JIT (Just-In-Time) Compiler
The JIT Compiler is a part of the JVM (Java Virtual Machine) that improves the
performance of Java applications by compiling frequently used bytecode into native
machine code at runtime.
Who Does This?
The JVM includes the JIT Compiler, which works alongside the Interpreter. Initially, the
JVM interprets the bytecode, but when a piece of code is executed multiple times, the
JIT Compiler compiles it into native code for faster execution.
How JIT Works?
1. JVM starts interpreting the bytecode line by line.
2. JIT detects "hot code" (frequently used methods or loops).
3. JIT compiles this hot code into native machine code and stores it in memory.
4. Future calls to this code execute directly in machine language, skipping
interpretation.
Unicode in Java
Unicode is a character encoding standard that allows Java to represent characters from
almost all languages and symbols worldwide.
Reference Types in Java
A reference type in Java refers to an object stored in memory, rather than holding a
direct value like primitive types. Instead of storing actual data, reference variables
store the memory address (reference) of an object.
1. Instance Variables (Non-Static Variables)
• Defined inside a class but outside any method or block.
• Each object gets its own copy of instance variables.
• Stored in heap memory (inside the object).
• Initialized when the object is created and destroyed when the object is garbage
collected.
Key Points:
✔ Belongs to each object separately.
✔ Different objects can have different values for the instance variable.
2. Static Variables (Class Variables)
• Declared with the static keyword inside a class but outside any method.
• Shared among all instances of the class (one copy per class).
• Stored in method area (not heap or stack).
• Initialized once when the class is loaded.
Key Points:
✔ Belongs to the class, not the object.
✔ Shared across all objects of the class.
✔ Can be accessed using ClassName.variableName (e.g., Student.college).
3. Local Variables
• Declared inside a method, constructor, or block.
• Scope is limited to the method/block they are declared in.
• Stored in stack memory.
• Not automatically initialized (must be assigned before use).
Key Points:
✔ Exists only within the method/block.
✔ Not accessible outside the method.
✔ Not automatically assigned a default value.
4. Final Variables (Constants)
• Declared using the final keyword.
• Once assigned, cannot be changed.
• Can be instance, static, or local.
• Must be initialized either at the time of declaration or in the constructor.
Key Points:
✔ Cannot be modified once assigned.
✔ Used to define constants.
✔ Final static variables are usually written in UPPER_CASE (e.g., PI or
MAX_VALUE).
Conclusion
✔ Instance variables belong to an object.
✔ Static variables belong to a class and are shared.
✔ Local variables exist only inside methods.
✔ Final variables are constants and cannot be modified.
Static Block vs. Non-Static Block
Blocks in Java are used for initializing variables and executing code before or when an
object is created.
Static block runs before main() method.
Used for static variable initialization.
Non-static block runs every time an object is created.
Executes before the constructor.
final Keyword
The final keyword in Java is used to restrict modification.
abstract Keyword
Key Points:
✔ Abstract class can have both abstract & concrete methods.
✔ Cannot create an object of an abstract class.
✔ Subclasses must override abstract methods.
Conclusion
✔ Static Block → Runs once when class loads.
✔ Non-Static Block → Runs before constructor, on object creation.
✔ Final Variable → Cannot change after assignment.
✔ Final Method → Cannot be overridden.
✔ Final Class → Cannot be inherited.
✔ Abstract Class → Cannot instantiate; used as a blueprint.
✔ Abstract Method → Must be implemented by subclasses.
OPERATORS IN JAVA
Java Constructors
Java constructors or constructors in Java is a terminology used to construct something
in our programs. A constructor in Java is a special method that is used to initialize
objects. The constructor is called when an object of a class is created. It can be used to
set initial values for object attributes.
In Java, a Constructor is a block of codes similar to the method. It is called when an
instance of the class is created. At the time of calling the constructor, memory for the
object is allocated in the memory. It is a special type of method that is used to initialize
the object. Every time an object is created using the new() keyword, at least one
constructor is called.
How Java Constructors are Different From Java Methods?
• Constructors must have the same name as the class within which it is defined it
is not necessary for the method in Java.
• Constructors do not return any type while method(s) have the return type
or void if does not return any value.
• Constructors are called only once at the time of Object creation while method(s)
can be called any number of times.
NOTE: The first line of a constructor is a call to super() or this(), (a call to a
constructor of a super-class or an overloaded constructor), if you don’t type in the
call to super in your constructor the compiler will provide you with a non-argument
call to super at the first line of your code, the super constructor must be called to
create an object:
If you think your class is not a subclass it actually is, every class in Java is the
subclass of a class object even if you don’t say extends object in your class
definition
• A constructor in Java can not be abstract, final, static, or Synchronized.
• Access modifiers can be used in constructor declaration to control its
access i.e which other class can call the constructo
Types of Constructors in Java
Now is the correct time to discuss the types of the constructor, so primarily there
are three types of constructors in Java are mentioned below:
• Default Constructor
• Parameterized Constructor
• Copy Constructor
1. Default Constructor in Java
A constructor that has no parameters is known as default constructor.
Implicit Default Constructor: If no constructor is defined in a class, the Java
compiler automatically provides a default constructor. This constructor doesn’t
take any parameters and initializes the object with default values, such as 0 for
numbers, null for objects.
Explicit Default Constructor: If we define a constructor that takes no parameters,
it’s called an explicit default constructor. This constructor replaces the one the
compiler would normally create automatically. Once you define any constructor
(with or without parameters), the compiler no longer provides the default
constructor for you.
2. Parameterized Constructor in Java
A constructor that has parameters is known as parameterized constructor. If we
want to initialize fields of the class with our own values, then use a parameterized
constructor.
// Java Program for Parameterized Constructor
import java.io.*;
class Geek {
// data members of the class.
String name;
int id;
Geek(String name, int id) {
this.name = name;
this.id = id;
class GFG
public static void main(String[] args)
// This would invoke the parameterized constructor.
Geek geek1 = new Geek("Avinash", 68);
System.out.println("GeekName :" + geek1.name
+ " and GeekId :" + geek1.id);
Remember: Does constructor return any value?
There are no “return value” statements in the constructor, but the constructor
returns the current class instance. We can write ‘return’ inside a constructor.
Now the most important topic that comes into play is the strong incorporation of
OOPS with constructors known as constructor overloading. Just like methods, we
can overload constructors for creating objects in different ways. The compiler
// Java Program to illustrate constructor overloading
// using same task (addition operation ) for different
// types of arguments.
import java.io.*;
class Geek {
// constructor with one argument
Geek(String name)
System.out.println("Constructor with one "
+ "argument - String : " + name);
// constructor with two arguments
Geek(String name, int age)
System.out.println(
"Constructor with two arguments : "
+ " String and Integer : " + name + " " + age);
// Constructor with one argument but with different
// type than previous..
Geek(long id)
System.out.println(
"Constructor with one argument : "
+ "Long : " + id);
class GFG {
public static void main(String[] args)
// Creating the objects of the class named 'Geek'
// by passing different arguments
// Invoke the constructor with one argument of
// type 'String'.
Geek geek2 = new Geek("Shikhar");
// Invoke the constructor with two arguments
Geek geek3 = new Geek("Dharmesh", 26);
// Invoke the constructor with one argument of
// type 'Long'.
Geek geek4 = new Geek(325614567);
}differentiates constructors on the basis of the number of parameters, types of
parameters, and order of the parameters.
3. Copy Constructor in Java
Unlike other constructors copy constructor is passed with another object which
copies the data available from the passed object to the newly created object.
Note: In Java,there is no such inbuilt copy constructor available like in other
programming languages such as C++, instead we can create our own copy
constructor by passing the object of the same class to the other instance(object) of
the class.
// Java Program for Copy Constructor
import java.io.*;
class Geek {
// data members of the class.
String name;
int id;
// Parameterized Constructor
Geek(String name, int id)
this.name = name;
this.id = id;
// Copy Constructor
Geek(Geek obj2)
this.name = obj2.name;
this.id = obj2.id;
class GFG {
public static void main(String[] args)
// This would invoke the parameterized constructor.
System.out.println("First Object");
Geek geek1 = new Geek("Avinash", 68);
System.out.println("GeekName :" + geek1.name
+ " and GeekId :" + geek1.id);
System.out.println();
// This would invoke the copy constructor.
Geek geek2 = new Geek(geek1);
System.out.println(
"Copy Constructor used Second Object");
System.out.println("GeekName :" + geek2.name
+ " and GeekId :" + geek2.id);
First Object
GeekName :Avinash and GeekId :68
Copy Constructor used Second Object
GeekName :Avinash and GeekId :68
Constructor Chaining In Java
Constructor chaining is the process of calling one constructor from another
constructor with respect to current object.
Constructor chaining can be done in two ways:
• Within same class: It can be done using this() keyword for constructors in
the same class
• From base class: by using super() keyword to call the constructor from the
base class.
Constructor chaining occurs through inheritance. A sub-class constructor’s task is
to call super class’s constructor first. This ensures that the creation of sub class’s
object starts with the initialization of the data members of the superclass. There
could be any number of classes in the inheritance chain. Every constructor calls up
the chain till the class at the top is reached.
Output:
75
The Default constructor
Rules of constructor chaining :
1. The this() expression should always be the first line of the constructor.
2. There should be at-least be one constructor without the this() keyword
(constructor 3 in above example).
3. Constructor chaining can be achieved in any order.
Constructor Chaining to other class using super() keyword :
Output:
Calling parameterized constructor of base
Calling parameterized constructor of derived
Inheritance in Java
Definition:
Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that
allows a class (child class) to inherit properties (fields) and behaviors (methods)
from another class (parent class).
Why Use Inheritance?
• Code reusability
• Improves maintainability
• Supports hierarchical relationships
Types of Inheritance in Java
1. Single Inheritance
A child class inherits from a single parent class.
2. Multilevel Inheritance
A class inherits from a derived class (a class that is already inheriting from another
class).
3. Hierarchical Inheritance
One parent class has multiple child classes.
4. Multiple Inheritance (Not Supported in Java using Classes)
Java does not support multiple inheritance using classes to avoid the Diamond
Problem. However, it can be achieved using interfaces.
5. Hybrid Inheritance (Not Supported Directly)
• Hybrid inheritance is a combination of multiple inheritance types.
• Java does not support hybrid inheritance with classes, but it can be achieved
using interfaces.
Access Modifiers in Java
In Java, Access modifiers helps to restrict the scope of a
class, constructor, variable, method, or data member. It provides security,
accessibility, etc. to the user depending upon the access modifier used with the
element.
Inner Classes in Java
An inner class is a class defined inside another class. It helps in grouping logically
related classes and improves encapsulation.
Types of Inner Classes in Java
1. Member Inner Class (Regular Inner Class)
2. Static Nested Class
3. Local Inner Class
4. Anonymous Inner Class
Member Inner Class (Regular Inner Class)
• A non-static class defined inside another class.
• Can access private members of the outer class.
• Requires an instance of the outer class to create an object.
2. Static Nested Class
• Declared using the static keyword.
• Does not need an instance of the outer class.
• Can only access static members of the outer class.
3. Local Inner Class
• A class defined inside a method.
• Can access local variables (only if they are final or effectively final).
• Used for encapsulating specific logic inside a method.
4. Anonymous Inner Class
• A class without a name.
• Created for one-time use.
• Used for implementing interfaces or extending classes inline.
What Does static Before a Class Mean in Java?
In Java, a class can only be declared static if it is a nested class (a class inside
another class).
A top-level class (a normal class) cannot be static because static means
"belonging to the class itself," and top-level classes don't belong to any other class.
Static Nested Class (Allowed)
A static nested class is a class inside another class that is declared static.
It can be accessed without creating an object of the outer class.
It can only access static members of the outer class.
It cannot access non-static (instance) members of the outer class.
Abstract Classes in Java
An abstract class in Java is a class that cannot be instantiated and is meant to be
extended by other classes. It can contain both abstract methods (without
implementation) and concrete methods (with implementation).
4⃣ Can an Abstract Class Have a Constructor?
Yes! Even though you cannot create objects of an abstract class, its constructor
runs when a subclass object is created.
Interfaces in Java
An interface in Java is a blueprint of a class that only contains abstract methods
(before Java 8). It is used to achieve full abstraction and multiple inheritance in
Java.
Polymorphism in Java
Polymorphism means "many forms"—a single method or object can behave
differently based on the context.
Java has two main types of polymorphism:
1⃣ Compile-Time Polymorphism (Static Binding)
2⃣ Runtime Polymorphism (Dynamic Binding)
1. Compile-Time Polymorphism (Static Binding)
What is it?
• Also called method overloading.
• The method to be executed is determined at compile time.
• Based on method signatures (method name + parameters).
• Achieved via Method Overloading.
2. Runtime Polymorphism (Dynamic Binding)
What is it?
• Also called method overriding.
• The method to be executed is determined at runtime.
• Achieved via Method Overriding.
• Uses upcasting to refer to subclass objects.
Upcasting & Downcasting
Upcasting (Automatic)
• When a subclass object is assigned to a superclass reference.
• Allowed automatically.
• Used in method overriding.
Downcasting (Manual)
• When a superclass reference is cast back to a subclass.
• Not automatic (must be done explicitly).
• ⚠ Risky (can cause ClassCastException)
Final Takeaways
✔ Compile-Time Polymorphism (Static Binding) → Done using method
overloading.
✔ Runtime Polymorphism (Dynamic Binding) → Done using method overriding.
✔ Upcasting → Assigning subclass object to a superclass reference ( Safe).
✔ Downcasting → Converting superclass reference back to subclass (⚠ Risky).
✔ Method calls depend on the reference type in static binding, but actual object
type in dynamic binding.