0% found this document useful (0 votes)
7 views

JAVA MODULE 3

BCS306A OOPS WITH JAVA

Uploaded by

abduljabbar.k
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

JAVA MODULE 3

BCS306A OOPS WITH JAVA

Uploaded by

abduljabbar.k
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 55

MODULE 3

 Inheritance: Inheritance Basics, Using super,


Creating a Multilevel Hierarchy, When Constructors
Are Executed, Method Overriding, Dynamic Method
Dispatch, Using Abstract Classes, Using final with
Inheritance, Local Variable Type Inference and
Inheritance, The Object Class.
 Interfaces: Interfaces, Default Interface Methods,
Use static Methods in an Interface, Private Interface
Methods.
Inheritance
 Inheritance is one of the key concepts of Object-Oriented Programming (OOP) in
Java.
 It allows a new class to inherit properties and behaviors (fields and methods)
from an existing class.
 This enables code reuse and establishes a hierarchical relationship between
classes.
1. Base Class (Super/Parent Class):
The class whose properties and methods are inherited is called the base class or
superclass.
It contains fields and methods that will be shared with subclasses.
2. Derived Class (Sub/Child Class):
The class that inherits from the base class is called the derived class or subclass.
It can extend the functionality of the base class or override its methods .
 In Java, inheritance is implemented using the extends keyword.
 A subclass uses extends to indicate that it is inheriting from a superclass.
 The general form of a class declaration that inherits a superclass is:
class subclass-name extends superclass-name
{ // body of class }
 The following program creates a superclass called A and a subclass called B.
class A {
int i, j;
void showij() {
System.out.println("i and j: " + i + " " + j);
} }
class B extends A {
int k;
void showk() {
System.out.println("k: " + k);
}
void sum() {
System.out.println("i+j+k: " + (i+j+k));
} }
class SimpleInheritance {
public static void main(String args[]) {
A superOb = new A();
B subOb = new B();
// The superclass may be used by itself.
superOb.i = 10;
superOb.j = 20;
System.out.println("Contents of superOb: ");
superOb.showij();
System.out.println();
/* The subclass has access to all public members of its superclass. */
subOb.i = 7;
subOb.j = 8;
subOb.k = 9;
System.out.println("Contents of subOb: ");
subOb.showij();
subOb.showk();
System.out.println();
System.out.println("Sum of i, j and k in subOb:");
subOb.sum();
 OUTPUT:
Contents of superOb:
i and j: 10 20
Contents of subOb:
i and j: 7 8
k: 9
Sum of i, j and k in subOb:
i+j+k: 24
Member Access and Inheritance
 A subclass includes all of the members of its superclass.
 But it cannot access those members of the superclass that have been declared as private.
class A {
int i; // public by default
private int j; // private to A
void setij(int x, int y) {
i = x;
j = y;
}
}
class B extends A {
int total;
void sum() {
total = i + j;
}
}
class Access {
public static void main(String args[]) {
B subOb = new B();
subOb.setij(10, 12);
subOb.sum();
System.out.println("Total is " + subOb.total);
} }
 This program will not compile because the reference to j inside the
sum( ) method of B causes an access violation.
 Since j is declared as private, it is only accessible by other members of
its own class.
 Subclasses have no access to it.
Using super
 In java super is a keyword used to refer to the superclass of the current object.
 It can be used in three main contexts:
 Calling superclass constructors
 Accessing superclass methods
 Accessing superclass fields

1. Calling superclass constructors


You can use super() to invoke a constructor of the superclass.
It must be the first statement in the subclass constructor.
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Dog extends Animal {
Dog(String name) {
// Calling the constructor of the superclass (Animal)
super(name);
}
void display() {
System.out.println("Dog's name: " + name);
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.display();
}
2. Accessing superclass methods
 You can use super.methodName() to call a method defined in
the superclass that has been overridden in the subclass.
class Animal {
void sound() {
System.out.println("Animal makes a sound");
} }
class Dog extends Animal {
void sound() {
System.out.println("Dog barks");
}
void printSounds() {
// Calling superclass method using super
super.sound(); // Calls the Animal's sound method
sound(); // Calls the Dog's overridden sound method
} }
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.printSounds();
3. Accessing superclass fields
 If the subclass has a field that hides a field in the
superclass, you can use super.fieldName to access the
superclass version of the field.
class Animal {
String name = "Animal";
}
class Dog extends Animal {
String name = "Dog";
void displayNames() {
System.out.println("Superclass name: " + super.name); // Accesses Animal's name
System.out.println("Subclass name: " + this.name); // Accesses Dog's name
}}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.displayNames();
}}
Creating a Multilevel Hierarchy

 In multilevel inheritance in Java, a class is derived from another class,


which in turn is derived from another class.
 This forms a chain of inheritance where a class inherits from its immediate
superclass, and it can also inherit from all classes up the hierarchy.
 Features of Multilevel Inheritance:
• The chain can continue for any number of levels.
• Each derived class inherits fields and methods from all its superclasses.
• The most specific class in the chain has access to all the methods and
attributes from its ancestors.
SYNTAX:
class A {
// Superclass
}

class B extends A {
// Derived class from A
}

class C extends B {
// Derived class from B (Multilevel inheritance)
}
// Base class or Superclass
class Animal {
void eat() {
System.out.println("Animal eats food");
} }
// Derived class (Subclass of Animal)
class Mammal extends Animal {
void walk() {
System.out.println("Mammal walks on land");
} }
// Derived class (Subclass of Mammal, which is a subclass of Animal)
class Dog extends Mammal {
void bark() {
System.out.println("Dog barks");
} }
public class Main {
public static void main(String[] args) {
// Creating an instance of the most specific class (Dog)
Dog dog = new Dog();
// Calling methods from different levels of the inheritance chain
dog.eat(); // Inherited from Animal
dog.walk(); // Inherited from Mammal
dog.bark(); // Defined in Dog
} }

Animal eats food


Mammal walks on land
Dog barks
Multilevel Inheritance with Constructors

 You can also use constructors in multilevel inheritance.


 When an object of a derived class is created, the constructor of the
superclass is invoked first (either explicitly or implicitly using SUPER())
// Base class or Superclass
class Animal {
Animal() {
System.out.println("Animal is created");
}
void eat() {
System.out.println("Animal eats food");
}
}
// Derived class (Subclass of Animal)
class Mammal extends Animal {
Mammal() {
// Calling the superclass constructor using super()
super();
System.out.println("Mammal is created");
}
void walk() {
System.out.println("Mammal walks on land");
}
}
 // Derived class (Subclass of Mammal)
class Dog extends Mammal {
Dog() {
// Calling the superclass constructor
super();
System.out.println("Dog is created");
}
void bark() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
// Create an instance of the Dog class
Dog dog = new Dog();
// Calling methods
dog.eat(); // Inherited from Animal
dog.walk(); // Inherited from Mammal
dog.bark(); // Defined in Dog
}
OUTPUT:

Animal is created
Mammal is created
Dog is created
Animal eats food
Mammal walks on land
Dog barks
Method Overriding
 Method overriding in Java occurs when a subclass provides a specific
implementation of a method that is already defined by its parent class.
 This allows the subclass to modify or extend the behavior of the parent class's
method.
 Key Points:
 Same Signature: The method in the subclass must have the same name,
return type, and parameters as in the parent class.
 @Override Annotation: While optional, it is good practice to use the
override annotation to indicate that a method is being overridden.
 Access Level: The access level of the overriding method cannot be more
restrictive than the method in the parent class.
 Final and Static Methods: Static methods cannot be overridden, and
methods marked as final cannot be overridden either.
 Polymorphism: Method overriding is a key aspect of achieving runtime
polymorphism in Java.
class Animal {
void sound() {
System.out.println("Animal makes a sound");
} }
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.sound(); // Outputs: Dog barks
}}

OUTPUT:
Dog barks
Dynamic Method Dispatch

 Dynamic method dispatch is the mechanism by which a call to an


overridden method is resolved at run time, rather than compile time.
 Dynamic method dispatch is important because this is how Java
implements run-time polymorphism.
 When a subclass overrides a method of the superclass, and you call
that method using a reference of the superclass pointing to the
subclass object.
 Java dynamically determines which method to invoke based on the
object being referred to at runtime, not the reference type.
 This is how polymorphism is achieved in Java.
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows");
} }
public class Main {
public static void main(String[] args) {
Animal myAnimal; // Declare reference of type Animal
myAnimal = new Dog(); // Refer to Dog object
myAnimal.sound();
myAnimal = new Cat(); // Refer to Cat object
myAnimal.sound();
}
}

OUTPUT:
Dog barks
Cat meows
 Key Points:
1. Superclass Reference: In dynamic method dispatch, the method is
invoked on a superclass reference that points to a subclass object.
2. Runtime Polymorphism: The decision of which method to invoke
is made at runtime, not during compile-time.
3. Method Overriding: Dynamic method dispatch is only possible
through method overriding. If a method is not overridden, the
superclass method will be invoked.
4. Importance in Java: It allows Java to implement polymorphism,
enabling the flexibility of having one interface and multiple
implementations.
Abstract Classes
 Abstract classes in Java are used to declare classes that cannot be
instantiated on their own.
 Abstract classes are used to provide a common base for subclasses
and may contain both abstract methods (methods without
implementation) and concrete methods (methods with
implementation).
 Abstract classes help to define a blueprint for subclasses to follow,
ensuring that they implement certain methods while allowing shared
functionality.
 To declare a class abstract, use the abstract keyword in front of the
class keyword at the beginning of the class declaration.
 There can be no objects of an abstract class. That is, an abstract
class cannot be directly instantiated with the new operator.
Key Features of Abstract Classes:
 Abstract Methods: A method declared without a body is called an
abstract method. It is meant to be overridden in subclasses.
 To declare an abstract method, use the general form:
abstract type name(parameter-list);
Concrete Methods: Abstract classes can also contain regular methods
(with implementations) that can be shared among subclasses.
Cannot Instantiate: You cannot create an object of an abstract class. It
must be subclassed.
Constructors: Abstract classes can have constructors, which can be used
by subclasses during object creation.
Polymorphism: Abstract classes support polymorphism, allowing a
subclass object to be referred to by a reference of the abstract class.
Syntax:
abstract class Animal {
// Abstract method (no implementation)
abstract void sound();

// Concrete method
void sleep()
{
System.out.println("This animal sleeps.");
}
}
// Abstract class
abstract class Animal {
// Abstract method (must be overridden by subclasses)
abstract void sound();
// Concrete method (optional for subclasses to use)
void sleep() {
System.out.println("This animal sleeps.");
}
}
// Subclass 1
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
// Subclass 2
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // Create Dog object
myDog.sound(); // Outputs: Dog barks
myDog.sleep(); // Outputs: This animal sleeps.

Animal myCat = new Cat(); // Create Cat object


myCat.sound(); // Outputs: Cat meows
myCat.sleep(); // Outputs: This animal sleeps.
}
}
 Usage of Abstract Classes:
• Common Template: When you have a base class with some common
functionality (concrete methods) and some abstract behavior (abstract
methods), abstract classes help enforce that the common behavior is
shared while subclasses are responsible for implementing specific
behaviors.
• Shared State: Abstract classes can also have fields (variables) that can
be shared and accessed by all subclasses.
 When to Use:
• Use abstract classes when you want to provide a common template or
base with shared functionality that subclasses must extend.
• Use abstract classes if some methods are the same for all subclasses,
while others need to be defined in a subclass-specific way.
Using final with Inheritance

 The keyword final has three uses.


 First, it can be used to create the equivalent of a named constant.
 The other two uses of final apply to inheritance.
 Using final to Prevent Overriding
 When you declare a method as final you are telling the compiler that
this method cannot be overridden by any subclasses.
 This is useful in cases where the functionality of the method should
remain unchanged across different inherited classes.
 It ensure that the method's behavior is consistent and preventing
accidental or intentional modifications.
class Parent {
public final void display() {
System.out.println("This method cannot be overridden.");
}
}

class Child extends Parent {


// Trying to override the display() method here would cause a compile-
time error
// public void display() {
// System.out.println("Attempting to override.");
// }
}
 Methods declared as final can sometimes provide a
performance enhancement:
 The compiler is free to calls them because compiler “knows”
they will not be overridden by a subclass.
 Normally, Java resolves calls to methods dynamically, at run
time. This is called late binding.
 final methods cannot be overridden, a call to one can be
resolved at compile time. This is called early binding
Using final to Prevent Inheritance

 If we want to prevent a class from being inherited, precede the


class declaration with final.
 Declaring a class as final implicitly declares all of its methods
as final, too.
 It is illegal to declare a class as both abstract and final.
 Since an abstract class is incomplete by itself and relies upon
its subclasses to provide complete implementations.
final class Vehicle {
public void drive() {
System.out.println("Driving the vehicle.");
}
}

// The following code will cause a compile-time error because Vehicle is final and
cannot be inherited
// class Car extends Vehicle {
// }
Local Variable Type Inference
 Local variable type inference was introduced in Java 10 with the var
keyword.
 This allows the compiler to infer the type of a local variable based on the
value it is initialized with.
 With var the type of a local variable is automatically inferred by the
compiler at compile time.
 This does not mean Java becomes dynamically typed
 The inferred type is still fixed and determined during compilation.
 For Example:
 var str = "Hello, World!"; // inferred as String
 var num = 10; // inferred as int
Local Variable Type Inference and Inheritance
 When using var in the context of inheritance, the inferred type will always be the
most specific type at the time of assignment.
 This means that when using an object with a parent-child relationship (inheritance),
the type inferred is the actual class of the object.
class Animal {
void makeSound() {
System.out.println("Animal sound");
} }
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
} }
public class Main {
public static void main(String[] args) {
var dog = new Dog(); // inferred as Dog
dog.makeSound(); // "Bark" is printed
The Object Class

 There is one special class, Object, defined by Java.


 All other classes are subclasses of Object
 That is, Object is a superclass of all other classes
 This means that a reference variable of type Object can refer
to an object of any other class
 Since arrays are implemented as classes, a variable of type
Object can also refer to any array
Object defines the following methods, which means that they are available
in every object
Interface
 An interface in Java is a reference type, similar to a class.
 An interface defines a contract or blueprint that a class can
implement.
 An interface can contain only constants, method signatures, default
methods, static methods, and nested types.
 Interfaces cannot contain instance fields or constructors.
 The methods in an interface are abstract by default, meaning they have
no body.
 A class that implements an interface must provide implementations for
all the methods declared in the interface unless the class is abstract.
 A class can implement multiple interfaces, which is Java's way of
supporting multiple inheritance .
Defining an Interface
 An interface is defined much like a class.
 This is the general form of an interface:
access interface name {
return-type method-name1(parameter-list);
return-type method-name2(parameter-list);
type final-varname1 = value;
type final-varname2 = value;
// ...
return-type method-nameN(parameter-list);
type final-varnameN = value;
}
// Defining an interface
interface Animal
{
void eat(); // abstract method
void sleep(); // abstract method
default void makeSound() { // default method
System.out.println("Some generic sound");
}
}
// Implementing the interface in a class
class Dog implements Animal {
public void eat() {
System.out.println("Dog eats");
}
public void sleep() {
System.out.println("Dog sleeps");
}
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.sleep();
dog.makeSound(); // This will call the overridden method
}
}
Default Interface Methods
 Default Interface Methods is a concept introduced in Java 8.
 It allows interfaces to have methods with concrete implementations.
 Prior to Java 8, all methods in an interface were abstract, meaning that they
couldn't have any method body or implementation.
 Key Features of Default Methods:
1. Optional Override: When an interface includes a default method,
implementing classes can choose to either use the default implementation
provided by the interface or override the method with their own
implementation.
2. Backward Compatibility: Default methods were introduced to ensure that
adding new methods to interfaces in Java doesn’t break the classes that already
implement them.
3. Multiple Inheritance of Behavior: If a class implements multiple interfaces,
and those interfaces have default methods with the same signature, the class
must resolve the conflict by overriding the method.
Static Methods in an Interface
 In Java 8 and later, interfaces can also define static methods.
 These methods belong to the interface itself and cannot be overridden by
implementing classes.
 Static methods in interfaces are used to define utility methods related to the
interface, which can be invoked directly on the interface rather than through
an instance of the implementing class.
 Key Features of Static Methods in Interfaces:
1. Belong to Interface: Static methods are part of the interface and not the
instances of the class that implement the interface.
2. Cannot Be Overridden: Classes that implement the interface cannot
override static methods.
3. Called via Interface: Static methods are called using the interface name,
similar to how static methods in classes are called using the class name.
interface Calculator {
// Abstract method
int add(int a, int b);

// Static method in the interface


static int multiply(int a, int b) {
return a * b;
}

// Another static method


static void printWelcome() {
System.out.println("Welcome to the Calculator Interface");
}
}
class SimpleCalculator implements Calculator {
public int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
// Calling static methods directly from the interface
int product = Calculator.multiply(3, 5);
System.out.println("Product: " + product);
Calculator.printWelcome();
// Using the implemented class
SimpleCalculator calc = new SimpleCalculator();
int sum = calc.add(10, 20);
System.out.println("Sum: " + sum);
}
}
Private Interface Methods
 In Java 9 and later, interfaces can have private methods.
 Private methods in interfaces allow you to encapsulate common functionality
shared by multiple default or static methods within the interface.
 These private methods cannot be accessed or overridden by implementing
classes, ensuring that they are used only inside the interface.
 Key Features of Private Methods in Interfaces:
1. Encapsulation: Private methods help reduce code duplication by
encapsulating common functionality that can be reused within default or static
methods
2. Not Visible to Implementing Classes: Implementing classes cannot access or
override private methods in the interface. They are for internal use within the
interface.
3. Usage: They can be called by default or static methods inside the interface,
making the interface more modular and reducing repetitive code.
 Syntax:
 There are two types of private methods in interfaces:
 Private Instance Methods: These can be called by default
methods in the interface.
 Private Static Methods: These can be called by static
methods in the interface.
interface Calculator {
// Abstract method
int add(int a, int b);
// Default method
default int subtract(int a, int b) {
logOperation("Subtraction");
return a - b;
}
// Static method
static int multiply(int a, int b) {
logStaticOperation("Multiplication");
return a * b;
}
// Private instance method, accessible by default methods
private void logOperation(String operation) {
System.out.println("Performing: " + operation);
}
// Private static method, accessible by static methods
private static void logStaticOperation(String operation) {
System.out.println("Performing: " + operation);
}
// Class implementing the interface
class SimpleCalculator implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
SimpleCalculator calc = new SimpleCalculator();

// Using the implemented add method


System.out.println("Sum: " + calc.add(5, 3));

// Using default method subtract


System.out.println("Difference: " + calc.subtract(10, 4));

// Using static method multiply


System.out.println("Product: " + Calculator.multiply(2, 3));
}
}

You might also like