ITE 2132 - Object Oriented Programming (1)
ITE 2132 - Object Oriented Programming (1)
Programming
Classes are typically declared using the class keyword followed by the
class name.
Example:
// Methods
public void start() {
// Code to start the car
}
2. Object:
When you create an object, you are creating a realization of the class
blueprint. Each object has its own set of attributes (also known as instance
variables or member variables) and can invoke methods defined in its
class.
Objects are created using the new keyword followed by the class name,
and you can assign it to a reference variable.
Example:
anotherCar.make = "Honda";
anotherCar.model = "Accord";
anotherCar.year = 2018;
anotherCar.start();
anotherCar.drive();
In this example, myCar and anotherCar are objects of the Car class. They each have
their own set of attributes ( make , model , year ) and can invoke methods ( start() ,
drive() ) defined in the Car class. This is the essence of class and object theory in
Java OOP.
Public vs Private
In Java, public and private are access modifiers used to control the visibility of
classes, methods, and fields within a program. Here's a breakdown of each:
1. Public:
This means that public elements are accessible outside of their own class
and are part of the class's public interface.
It's commonly used for methods and fields that need to be accessible from
other parts of the program.
Example:
1. Private:
It's often used for fields and methods that should not be accessible or
modified from outside the class.
Example:
1. Instance Variables:
Instance variables are declared within a class but outside of any method,
constructor, or block.
They are associated with objects of the class and are created when an
object is instantiated (i.e., when new keyword is used).
Instance variables exist as long as the object they belong to exists. They
are destroyed when the object is garbage collected.
Example:
// Constructor
public MyClass(int x, String name) {
this.x = x;
this.name = name;
}
}
1. Local Variables:
Local variables are declared within a method, constructor, or block and are
accessible only within that specific scope.
They are created when the method, constructor, or block is entered, and
they are destroyed when it exits.
Example:
Scope: Instance variables are accessible throughout the class (within all
methods, constructors, and blocks), while local variables are accessible only
within the method, constructor, or block where they are declared.
Lifetime: Instance variables exist as long as the object they belong to exists,
while local variables exist only within the scope in which they are declared and
are destroyed when that scope exits.
Return Statement
In Java, the return statement is used to exit a method and optionally return a value
to the caller of the method. Here are the key points about the return statement:
1. Syntax:
return expression;
If the method has any remaining code after the return statement, it will not
be executed.
If the method has a return type other than void , it must return a value
using the return statement.
The return value must be compatible with the method's return type.
If the method has a void return type, it does not return any value, and the
return statement can be used without specifying an expression.
A method can have multiple return statements, but only one of them will
be executed.
5. Usage Examples:
Returning a value:
The return statement is fundamental for controlling the flow of execution within
methods and for providing results back to the caller of the method.
Encapsulation
Encapsulation is one of the four fundamental principles of object-oriented
programming (OOP) and is a key concept in Java. It refers to the bundling of data
(attributes) and methods that operate on the data into a single unit, called a class.
The class then controls access to its data by hiding its implementation details and
providing a well-defined interface for interacting with the data.
1. Access Modifiers:
2. Private Fields:
This prevents direct access to the fields from outside the class, ensuring
data integrity and encapsulation.
Example:
Example:
// Getter methods
public String getMake() {
return make;
}
// Setter methods
public void setMake(String make) {
this.make = make;
}
1. Encapsulation Benefits:
Static Methods
Static methods in Java are methods that belong to a class rather than to instances
(objects) of the class. These methods are associated with the class itself, not with
any particular object instance. Here are the key points about static methods:
1. Declaration:
Static methods are declared using the static keyword before the return
type in the method signature.
Static methods can be called using the class name, followed by the dot
operator ( . ), and then the method name.
They can also be called using an object reference, but this is generally
discouraged because it can be confusing.
They can only directly access static variables (class variables) and other
static methods.
Utility methods: Static methods are often used to define utility methods
that perform common tasks and do not rely on the state of any particular
object.
Helper methods: They are useful for defining helper methods that are used
across multiple instances of the class.
Method Overloading
Method overloading is a feature in Java that allows a class to have multiple
methods with the same name but different parameter lists within the same class.
Here are the key points about method overloading:
1. Method Signature:
For method overloading, methods must have the same name but different
parameter lists. The parameter lists can differ in terms of the number of
parameters, types of parameters, or both.
2. Return Type:
The return type of the method can be the same or different for overloaded
methods. Method overloading is not based on the return type; it's based
on the method signature (name and parameters).
3. Access Modifier:
4. Example:
When a method is called, Java matches the method call with the
appropriate method based on the number and type of arguments provided.
Inheritance
Inheritance is one of the fundamental concepts of object-oriented programming
(OOP), and Java fully supports it. It enables one class (subclass or derived class)
to inherit properties and behaviors from another class (superclass or base class).
Here are the key points about inheritance in Java:
The superclass is the class being inherited from, and the subclass is the
class that inherits from the superclass.
2. Extends Keyword:
To create a subclass, you use the extends keyword followed by the name
of the superclass.
Example:
class Animal {
// Superclass (or base class)
void eat() {
System.out.println("Animal is eating");
}
}
Subclasses can access the members of their superclass using the super
keyword.
Example:
1. Method Overriding:
The method signature (name and parameters) must be the same in both
the superclass and the subclass.
2. Single Inheritance:
Java supports single inheritance, meaning a class can only inherit from
one superclass.
3. Multilevel Inheritance:
class Animal {
// Superclass
}
Overriding
Method overriding in Java allows a subclass to provide a specific implementation
of a method that is already defined in its superclass. This allows for polymorphic
behavior, where a subclass can define its own behavior for a method inherited
from its superclass. Here are the key points about method overriding in Java:
1. Method Signature:
To override a method in a subclass, the method must have the same name,
parameters, and return type (or covariant return type) as the method in the
superclass.
2. @Override Annotation:
While not required, it's a good practice to use the @Override annotation
when overriding a method. This annotation helps in avoiding accidental
3. Access Modifier:
The access modifier of the overriding method can be the same or wider
than the access modifier of the overridden method in the superclass.
4. Return Type:
The return type of the overriding method must be the same as, or a
subtype of, the return type of the overridden method. Covariant return
types are allowed, which means the subclass method can return a more
specific type than the superclass method.
5. Example:
class Animal {
void makeSound() {
System.out.println("Animal makes a sound");
}
}
Example:
Abstract Class
In Java, an abstract class is a class that cannot be instantiated directly and may
contain abstract methods, concrete methods, or both. Here are the key points
about abstract classes in Java:
An abstract class is declared using the abstract keyword before the class
keyword.
2. Concrete Methods:
3. Usage:
1. Instantiation:
Example:
Abstract classes provide a way to define common behavior and structure for
related classes, while allowing subclasses to provide specific implementations for
abstract methods. They are an important tool for achieving abstraction,
inheritance, and polymorphism in Java.
Final
The final keyword is a versatile modifier that can be applied to variables,
methods, and classes, each having a specific effect. Here’s a detailed explanation
of the final keyword in each of these contexts:
1. Final Variables
When a variable is declared as final , it means that its value cannot be changed
once it is initialized. This applies to both primitive data types and reference types.
In the case of reference types, the reference itself cannot be changed, but the
object it refers to can be modified.
2. Final Methods
A method declared as final cannot be overridden by subclasses. This is useful
when you want to prevent a method from being altered by any subclass.
Example
class Parent {
public final void show() {
System.out.println("This is a final method.");
}
}
3. Final Classes
A class declared as final cannot be subclassed. This is useful when you want to
prevent inheritance for security reasons or to maintain the integrity of the class's
Example
Final Parameters
In addition to variables, the final keyword can be used with method parameters.
This prevents the parameter from being reassigned within the method.
Example
static final fields are constants that belong to the class rather than any instance,
Example
Summary of Usage
Final Variables: Prevent reassignment.
Using the final keyword helps in designing robust and secure applications by
controlling how variables, methods, and classes can be modified or extended.
Constructor
A constructor in Java is a special type of method that is called when an object of a
class is instantiated. Constructors are used to initialize the state of an object,
typically by setting initial values for its fields. They have the same name as the
class and do not have a return type, not even void.
2. No Return Type: Constructors do not have a return type, not even void .
It initializes the object with default values (e.g., null for objects, 0 for
numeric types, false for boolean).
class Example {
int value;
String name;
}
2. Parameterized Constructor:
class Example {
int value;
String name;
3. No-Argument Constructor:
A constructor that does not take any arguments but can be explicitly
defined to perform specific initializations.
class Example {
int value;
String name;
Example() {
this.value = 10;
this.name = "Default";
}
}
Constructor Overloading
Just like methods, constructors can be overloaded, meaning you can have
multiple constructors with different parameter lists within the same class.
// No-argument constructor
Example() {
this.value = 0;
this.name = "No Name";
}
// Parameterized constructor
Example(int value) {
this.value = value;
this.name = "No Name";
}
Polymorphism
Polymorphism in Java is a fundamental concept in object-oriented programming
that allows objects to be treated as instances of their parent class rather than their
actual class. This promotes flexibility and integration by enabling a single interface
to represent different underlying forms (data types). Java achieves polymorphism
in two primary ways: compile-time (or static) polymorphism and runtime (or
dynamic) polymorphism.
Types of Polymorphism
1. Compile-time Polymorphism (Static Polymorphism)
Compile-time Polymorphism
Compile-time polymorphism is achieved through method overloading and
operator overloading.
Method Overloading
Method overloading occurs when multiple methods in the same class have the
same name but different parameters (different type, number, or both).
class Example {
void display(int a) {
System.out.println("Argument: " + a);
}
void display(String b) {
System.out.println("Argument: " + b);
}
}
Runtime Polymorphism
Runtime polymorphism is achieved through method overriding. It occurs when a
subclass provides a specific implementation of a method that is already defined in
its superclass.
Method Overriding
Method overriding allows a subclass to provide a specific implementation for a
method that is already defined in its superclass.
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
In this example, the sound method is overridden in the Dog class, and the actual
method to be called is determined at runtime based on the object type.
Benefits of Polymorphism
1. Code Reusability: Polymorphism promotes the reuse of code by allowing the
same interface to be used for different implementations.
Key Concepts
Inheritance: Polymorphism relies on inheritance, where a subclass inherits
properties and methods from a superclass.
Method Overloading: Multiple methods with the same name but different
parameters within the same class.
Example of Polymorphism
Here is an example demonstrating both compile-time and runtime polymorphism:
class Shape {
void draw() {
// Runtime polymorphism
Shape shape;
shape = new Circle();
shape.draw(); // Outputs "Drawing a circle"
// Overloaded methods
static void display(int a) {
System.out.println("Argument: " + a);
}
static void display(String b) {
Example Scenario
Let's define a simple inheritance hierarchy to illustrate the concepts of parent and
child objects.
class Animal {
String name;
Animal(String name) {
this.name = name;
}
void makeSound() {
System.out.println(name + " makes a sound");
}
}
@Override
void makeSound() {
System.out.println(name + " barks");
}
void fetch() {
System.out.println(name + " fetches a ball");
}
}
@Override
void makeSound() {
System.out.println(name + " meows");
}
void scratch() {
System.out.println(name + " scratches");
}
}
Parent Object
Child Objects
Explanation
1. Parent Object:
The animal variable is an instance of the Animal class (the parent class). It
has access to the makeSound method defined in the Animal class.
Animal animal = new Animal("Generic Animal"); creates a new Animal object with
the name "Generic Animal".
2. Child Objects:
The dog variable is an instance of the Dog class (a child class of Animal ). It
has access to the makeSound method from Animal , which it overrides, and it
also has its own method fetch .
Dog dog = new Dog("Buddy"); creates a new Dog object with the name "Buddy".
The cat variable is an instance of the Cat class (another child class of
Animal ). It overrides the makeSound method and has its own method scratch .
Upcasting
Upcasting is the process of treating a child object as if it were a parent object.
This is done implicitly and allows you to use a child object where a parent object is
expected.
In this example, Dog is upcast to Animal . The animal reference can only call
methods available in the Animal class, even though it points to a Dog object.
Downcasting
Downcasting is the process of treating a parent object as if it were a child object.
This requires an explicit cast and should be done carefully, often with a type
check.
Real-World Analogy
Consider a general vehicle and specific types of vehicles:
Car and Bicycle (Child Classes): Specific types of vehicles with additional
properties and behaviors.
void honk() {
System.out.println("Car honks");
}
}
void ringBell() {
System.out.println("Bicycle rings bell");
}
}
Summary
Parent Object: An instance of the superclass.
Child Object: An instance of the subclass that inherits from the superclass.
Incorrect Downcasting
When you try to downcast an object to a subclass that it does not actually belong
to, a ClassCastException is thrown.
Example:
What is ClassCastException ?
ClassCastException is a runtime exception that is thrown when an attempt is made to
cast an object to a subclass of which it is not an instance. This exception can be
avoided by using type checking before performing a downcast.
Example Scenario
Let's revisit the Animal , Dog , and Cat classes:
class Animal {
void makeSound() {
System.out.println("Animal makes a sound");
}
}
void fetch() {
System.out.println("Dog fetches a ball");
}
}
void scratch() {
System.out.println("Cat scratches");
}
}
Explanation
1. Upcasting:
3. Downcasting:
Perform the downcast. Since the type check passed, this cast is safe,
and the dog reference can now access methods specific to the Dog
class.
Structure
Imagine the following classes:
A
/ \
B C
\ /
D
Issues
When Class D inherits from both Class B and Class C, it inherits the members
(attributes and methods) of Class A twice: once through Class B and once
through Class C. This creates several issues:
But Java avoids the Diamond Problem altogether by not supporting multiple
inheritance of classes. Instead, it allows multiple inheritance through
interfaces. Since interfaces do not hold state (attributes), the ambiguity
problem is avoided.
Interface
In Java, interfaces are a fundamental part of its object-oriented programming
paradigm, providing a way to achieve abstraction and multiple inheritance. An
interface in Java is a reference type, similar to a class, that can contain only
constants, method signatures, default methods, static methods, and nested types.
The methods in interfaces are abstract by default, meaning they do not have a
body and must be implemented by classes that choose to implement the interface.
Here are the key aspects and features of interfaces in Java:
4. Static Methods: Interfaces can also have static methods. These methods
belong to the interface class and can be called without an instance of the
implementing class.
Implementing Interfaces
When a class implements an interface, it must provide concrete implementations
for all the abstract methods declared in the interface. If it does not, the class must
be declared abstract.
@Override
public void sleep() {
System.out.println("Dog is sleeping.");
Interface Inheritance
Interfaces can extend other interfaces, just like classes. This allows for the
creation of more specific interfaces based on more general ones.
@Override
public void play() {
System.out.println("Dog is playing.");
}
}
Example
Here’s a complete example demonstrating the use of interfaces:
@Override
public void sleep() {
System.out.println("Dog is sleeping.");
@Override
public void play() {
System.out.println("Dog is playing.");
}
}
In this example, the Dog class implements both Animal and Pet interfaces,
providing concrete implementations for all abstract methods and using the default
method from Animal . This demonstrates the flexibility and power of using
interfaces in Java.