Class: Intermediate
Inheritance
Inheritance is a mechanism in Java that allows one class to inherit the properties and methods of another class. The class that inherits is called the subclass or derived class, and the class from which it inherits is called the superclass or base class. Inheritance promotes code reusability and allows for the creation of a hierarchical structure of classes.
Example
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
public void bark() {
System.out.println(name + " is barking.");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.eat(); // Output: Buddy is eating.
dog.bark(); // Output: Buddy is barking.
}
}Hereβs the breakdown of the code:
- The program has a class named
Animal. This class is likely a superclass for different types of animals.- The
Animalclass has a single protected instance variablenameof typeString. The keywordprotectedmeans the variable is accessible within its own class, to subclasses, and also to classes in the same package. - The
Animalclass has a constructor which takes aStringargument. This constructor is used to initialize thenameattribute of anAnimalobject. - The
Animalclass has a method calledeat(). This method, when called, will print to the console thenameof theAnimalobject and a message stating that it is eating.
- The
- The program has another class named
Dog. This class is a subclass ofAnimal, inheriting all of theAnimalclass’s properties and methods.- The
Dogclass has a constructor which also takes aStringargument. This constructor calls the superclass constructor (super(name)) to initialize thenameof theDogobject. - The
Dogclass has a method calledbark(). This method, when called, will print to the console thenameof theDogobject and a message stating that it is barking.
- The
- There is a
Mainclass that contains themainmethod, the entry point of the program.- Inside the
mainmethod, aDogobject is created named “Buddy”. - The
eat()method is called on theDogobject, which prints “Buddy is eating.” to the console. - The
bark()method is then called on theDogobject, which prints “Buddy is barking.” to the console.
- Inside the
Polymorphism and Method Overloading
Polymorphism is the ability of an object to take on many forms. In Java, polymorphism allows a single method or class to have multiple implementations. There are two types of polymorphism in Java: compile-time polymorphism (method overloading) and runtime polymorphism (method overriding).
Example
class Animal {
public void makeSound() {
System.out.println("Animal is making a sound.");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog is barking.");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
Animal dog = new Dog();
animal.makeSound(); // Output: Animal is making a sound.
dog.makeSound(); // Output: Dog is barking.
}
}Here’s a breakdown of the code:
- Animal class definition: The code starts with a definition of a class named “Animal”. This class has a public method called
makeSound(), which when called, prints “Animal is making a sound.” to the console. - Dog class definition: Then we have a class named “Dog” which is a subclass of the “Animal” class. This is signified by the
extends Animalin the class definition. The Dog class overrides themakeSound()method from the Animal class. This means that, when a Dog object calls themakeSound()method, it will print “Dog is barking.” instead of “Animal is making a sound.”. - Main class and main method: The Main class contains the
mainmethod, which is the entry point to the program. - Creating Animal instance: Inside the
mainmethod, an object namedanimalof class Animal is instantiated. - Creating Dog instance: After that, an object named
dogof class Dog is instantiated, but it’s interesting to note that it is declared as an Animal type. This is known as “upcasting” - an instance of a subclass is treated as an instance of the superclass. This is possible because every Dog is an Animal (due to inheritance). - Calling the makeSound() method: Finally, the
makeSound()method is called on bothanimalanddoginstances. Foranimal, it calls themakeSound()method defined in the Animal class, while fordog, it calls themakeSound()method defined in the Dog class. This is an example of method overriding and polymorphism in Java. Even though thedogobject is declared as an Animal type, it still uses the Dog’s version ofmakeSound()because the actual object is a Dog.
The output of the code is as follows:
- “Animal is making a sound.” is printed when the
makeSound()method is called on theanimalobject. - “Dog is barking.” is printed when the
makeSound()method is called on thedogobject.
Instance Initializers (Non-static initialization blocks)
Instance initializers, also known as non-static initialization blocks, are used to initialize the instance data members of a class. They are executed each time an object of the class is created before the constructor is called. Instance initializers are helpful when performing some initialization logic familiar to all class constructors.
Example
package com.ayokoding.cookbook.java_class.intermediate.instance_initializers;
class Animal {
private String species;
{
// Instance initializer block
species = "Unknown";
System.out.println("Instance initializer block executed.");
}
public Animal() {
System.out.println("Constructor executed. Species: " + species);
}
public String getSpecies() {
return species;
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
// Output:
// Instance initializer block executed.
// Constructor executed. Species: Unknown
System.out.println(animal.getSpecies()); // Output: Unknown
}
}Here’s the explanation of this Java code:
- Class Declaration: The
Animalclass is declared. This class represents a certain type of object in Java. - Private Variable: Inside the
Animalclass, there’s a private variablespeciesof type String. This variable is meant to hold the species of the animal object. Being private, it is only accessible within theAnimalclass. - Instance Initializer Block: This is a block of code that’s executed every time an instance of the
Animalclass is created. It is defined by the braces{}without any keyword. In this case, it sets thespeciesvariable to “Unknown” and then prints a message indicating it has been executed. - Constructor: This is the
Animal()constructor, called when a newAnimalobject is created. It prints a message showing that it has been executed and shows the species of the animal, which at this point would be “Unknown” as set by the instance initializer block. - Getter Method: The
getSpecies()method is a getter method for thespeciesvariable. It returns the current value ofspecies. - Main Class and Method: The
Mainclass is defined with amainmethod. Themainmethod is the entry point for the program. - Animal Object Creation: Inside the
mainmethod, a newAnimalobject is created. This triggers the instance initializer block and the constructor, resulting in the output “Instance initializer block executed” followed by “Constructor executed. Species: Unknown”. - Getter Method Call: Finally,
animal.getSpecies()is called to get the species of the animal, which is then printed out. At this point, the species is still “Unknown”, so “Unknown” is printed.
The specific order of events in this program is important to understand. When a new Animal object is created, the instance initializer block is executed first, setting the species to “Unknown”. After that, the constructor is called, which prints the species “Unknown” at this point.
Static Initializers
Static initializers are used to initialize the static data members of a class. They are executed only once when the class is loaded into memory. Static initializers are helpful when performing some one-time initialization for static variables or setting up static resources.
Example
class Animal {
private static int count;
static {
// Static initializer block
count = 0;
System.out.println("Static initializer block executed.");
}
public Animal() {
count++;
System.out.println("Constructor executed. Count: " + count);
}
public static int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) {
new Animal();
new Animal();
// Output:
// Static initializer block executed.
// Constructor executed. Count: 1
// Constructor executed. Count: 2
System.out.println(Animal.getCount()); // Output: 2
}
}Here’s the explanation of this Java code:
class Animal: This is the class definition for anAnimal. This class will have methods and attributes that define the properties and behavior of an animal in the code.private static int count;: This line declares aprivatestaticinteger namedcount. As astaticvariable, it belongs to the class itself, not to individual instances of the class. This means all instances of theAnimalclass share this singlecountvariable. Theprivatekeyword means it can only be accessed within this class.static { ... }block: This is a static initializer block. It is executed once when the class is loaded into the memory. This code initializes thecountvariable to0and prints a message “Static initializer block executed.” to the console.public Animal() { ... }: This is the constructor for theAnimalclass. This constructor is called every time a new instance ofAnimalis created. It increments thecountby one and prints the message “Constructor executed. Count: " followed by the current value ofcount.public static int getCount(): This is a static method which returns the current value ofcount. As astaticmethod, it can be called on the class itself, not on class instances. Thepublickeyword means it can be accessed from outside this class.public class Main { ... }: This is theMainclass where the program starts execution.public static void main(String[] args) { ... }: This is themainmethod. It is the entry point of any Java application. The JVM starts execution from this method.new Animal(); new Animal();: These lines are creating two new instances of theAnimalclass. For each instance, the constructor ofAnimalclass is invoked which increments thecountby one and prints the message. Therefore, thecountbecomes2and the messages “Constructor executed. Count: 1” and “Constructor executed. Count: 2” are printed to the console.System.out.println(Animal.getCount());: This line calls the static methodgetCount()of theAnimalclass and prints the returned value. Sincecountis2, it prints2to the console.
Inner/Nested Classes
In Java, a class can be defined within another class, called a nested class or inner class. Inner classes have access to the members of the enclosing class, including private members. Java has four types of nested classes: static nested classes, non-static nested classes (inner classes), local classes, and anonymous classes.
Example
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
class Inner {
public void innerMethod() {
System.out.println("Inner method. Name: " + name);
}
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal("Lion");
Animal.Inner inner = animal.new Inner();
inner.innerMethod(); // Output: Inner method. Name: Lion
}
}Here’s a breakdown of the Java code:
class Animal: This is the declaration of a class namedAnimal.private String name;: A private instance variablenameof typeStringis declared in theAnimalclass. Private means this variable can only be accessed within theAnimalclass itself.public Animal(String name): This is a constructor for theAnimalclass. It takes a string argument and assigns it to the instance variablename. The keywordthisis used to reference the current instance of the class.public void eat(): This is an instance method namedeat. It does not return any value (void). When this method is called, it prints the name of the animal along with the string “is eating”.class Inner: This is an inner class within theAnimalclass. An inner class is a class declared inside another class, giving it access to the outer class’s private variables and methods.public void innerMethod(): This is a method in the inner classInner. When this method is called, it prints the string “Inner method. Name: " followed by the value ofname. SinceInneris an inner class, it has access toAnimal’s private variablename.public class Main: This is the declaration of another class namedMain. This class contains themainmethod, which is the entry point of the Java program.public static void main(String[] args): This is themainmethod. The JVM starts executing the program from this method.Animal animal = new Animal("Lion");: An instance ofAnimalis created with the name “Lion”, and the reference to this instance is stored in theanimalvariable.Animal.Inner inner = animal.new Inner();: An instance of the inner classInneris created using theanimalinstance. A reference to this inner class instance is stored in theinnervariable.inner.innerMethod();: TheinnerMethodof theInnerclass is called using theinnerinstance. The output is “Inner method. Name: Lion” sincenamewas set to “Lion” when theAnimalinstance was created.
Further Readings
- Oracle Java Tutorials: Inheritance
- GeeksforGeeks: Inheritance in Java
- Oracle Java Tutorials: Polymorphism
- Baeldung: Polymorphism in Java
- Oracle Java Tutorials: Overriding and Hiding Methods
- Oracle Java Tutorials: Initialization Blocks
- Oracle Java Tutorials: Initialization Blocks
- Oracle Java Tutorials: Nested Classes