JAVA MODULE 3
JAVA MODULE 3
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 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
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.
// 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