# data[].attributes.body
La herencia en programación permite crear nuevas clases basadas en clases existentes. La clase que hereda se llama clase derivada o subclase, y la clase original se llama clase base o superclase.

# data[].attributes.body
El polimorfismo es la capacidad de un objeto de tomar muchas formas. En programación, esto permite a las clases derivadas compartir la misma interfaz o método que la clase base, pero comportarse de manera diferente.

# data[].attributes.body
La herencia facilita la reutilización de código y permite la creación de una jerarquía de clases. Esto ayuda a organizar y estructurar el código de manera eficiente.

# data[].attributes.body
El polimorfismo permite el uso de una sola interfaz para múltiples tipos de objetos, lo que hace que el código sea más flexible y fácil de mantener.

# data[].attributes.body
En este ejemplo, la clase `Perro` hereda de la clase `Animal`, lo cual le permite reutilizar los métodos de la clase `Animal` y añadir sus propios métodos específicos.

# data[].attributes.body
Aquí mostramos cómo diferentes clases derivadas pueden sobrescribir el mismo método de la clase base para comportarse de manera distinta.

# data[].attributes.body
En lenguajes como C++, una clase puede heredar de más de una clase base. Este es un ejemplo de cómo funciona la herencia múltiple.

# data[].attributes.body
En C#, el polimorfismo se logra mediante la implementación de interfaces y la sobrescritura de métodos. Aquí hay un ejemplo práctico.

# data[].attributes.body
Esta guía detallada explica los conceptos básicos y avanzados de la herencia en la programación orientada a objetos.

# data[].attributes.attachment_link.readable_text
Inheritance is one of the core concepts of object-oriented programming (OOP) languages. It is a mechanism where you can to derive a class from another class for a hierarchy of classes that share a set of attributes and methods.

You can use it to declare different kinds of exceptions, add custom logic to existing frameworks, and even map your domain model to a database.

Try Stackify's free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.

Declare an inheritance hierarchy

In Java, each class can only be derived from one other class. That class is called a superclass, or parent class. The derived class is called subclass, or child class.

You use the keyword extends to identify the class that your subclass extends. If you don't declare a superclass, your class implicitly extends the class . Object is the root of all inheritance hierarchies; it's the only class in Java that doesn't extend another class.

The following diagram and code snippets show an example of a simple inheritance hierarchy.

The class BasicCoffeeMachine doesn't declare a superclass and implicitly extends the class Object. You can clone the CoffeeMachine example project on GitHub.

package org.thoughts.on.java.coffee;
import java.util.HashMap;
import java.util.Map;

public class BasicCoffeeMachine {
    protected Map configMap;
    protected Map beans;
    protected Grinder grinder;
    protected BrewingUnit brewingUnit;

    public BasicCoffeeMachine(Map beans) {
        this.beans = beans;
        this.grinder = new Grinder();
        this.brewingUnit = new BrewingUnit();

        this.configMap = new HashMap();
        this.configMap.put(CoffeeSelection.FILTER_COFFEE, new Configuration(30, 480));
    }

    public Coffee brewCoffee(CoffeeSelection selection) throws CoffeeException {
        switch (selection) {
            case FILTER_COFFEE:
                return brewFilterCoffee();
            default:
                throw new CoffeeException("CoffeeSelection [" + selection + "] not supported!");
        }
    }

    private Coffee brewFilterCoffee() {
        Configuration config = configMap.get(CoffeeSelection.FILTER_COFFEE);

        // grind the coffee beans
        GroundCoffee groundCoffee = this.grinder.grind(
            this.beans.get(CoffeeSelection.FILTER_COFFEE), config.getQuantityCoffee());

        // brew a filter coffee
        return this.brewingUnit.brew(
            CoffeeSelection.FILTER_COFFEE, groundCoffee, config.getQuantityWater());
    }

    public final void addBeans(CoffeeSelection sel, CoffeeBean newBeans)
        throws CoffeeException {
        CoffeeBean existingBeans = this.beans.get(sel);

        if (existingBeans != null) {
            if (existingBeans.getName().equals(newBeans.getName())) {
                existingBeans.setQuantity(existingBeans.getQuantity() + newBeans.getQuantity());
            } else {
                throw new CoffeeException(
                    "Only one kind of beans supported for each CoffeeSelection.");
            }
        } else {
            this.beans.put(sel, newBeans);
        }
    }
}

The class PremiumCoffeeMachine is a subclass of the BasicCoffeeMachine class.

package org.thoughts.on.java.coffee;
import java.util.Map;

public class PremiumCoffeeMachine extends BasicCoffeeMachine {
    public PremiumCoffeeMachine(Map beans) {
        // call constructor in superclass
        super(beans);

       // add configuration to brew espresso
         this.configMap.put(CoffeeSelection.ESPRESSO, new Configuration(8, 28));
    }

    private Coffee brewEspresso() {
        Configuration config = configMap.get(CoffeeSelection.ESPRESSO);

        // grind the coffee beans
        GroundCoffee groundCoffee = this.grinder.grind(
            this.beans.get(CoffeeSelection.ESPRESSO), config.getQuantityCoffee());

        // brew an espresso
        return this.brewingUnit.brew(
            CoffeeSelection.ESPRESSO, groundCoffee, config.getQuantityWater());
    }

    public Coffee brewCoffee(CoffeeSelection selection) throws CoffeeException {
        if (selection == CoffeeSelection.ESPRESSO) {
            return brewEspresso();
        } else {
            return super.brewCoffee(selection);
        }
    }
}

Inheritance and access modifiers

Access modifiers define what classes can access an attribute or method. In one of my previous posts on encapsulation, I showed you how you could use them to implement an information-hiding mechanism. But that's not the only case where you need to be familiar with the different modifiers. They also affect the entities and attributes that you can access within an inheritance hierarchy.

Here's is a quick overview of the different modifiers:

Private attributes or methods can only be accessed within the same class.

Attributes and methods without an access modifier can be accessed within the same class, and by all other classes within the same package.

Protected attributes or methods can be accessed within the same class, by all classes within the same package, and by all subclasses.

Public attributes and methods can be accessed by all classes.

As you can see in that list, a subclass can access all protected and public attributes and methods of the superclass. If the subclass and superclass belong to the same package, the subclass can also access all package-private attributes and methods of the superclass.

I do that twice in the constructor of the PremiumCoffeeMachine class.

public PremiumCoffeeMachine(Map beans) {
    // call constructor in superclass
        super(beans);

    // add configuration to brew espresso
    this.configMap.put(CoffeeSelection.ESPRESSO, new Configuration(8, 28));
}

I first use the keyword super to call the constructor of the superclass. The constructor is public, and the subclass can access it. The keyword super references the superclass. You can use it to access an attribute, or to call a method of the superclass that gets overridden by the current subclass. But more about that in the following section.

The protected attribute configMap gets defined by the BasicCoffeeMachine class. By extending that class, the attribute also becomes part of the PremiumCoffeeMachine class, and I can add the configuration that's required to brew an espresso to the Map.

Method overriding

Inheritance not only adds all public and protected methods of the superclass to your subclass, but it also allows you to replace their implementation. The method of the subclass then overrides the one of the superclass. That mechanism is called polymorphism.

I use that in the PremiumCoffeeMachine class to extend the coffee brewing capabilities of the coffee machine. The brewCoffee method of the BasicCoffeeMachine method can only brew filter coffee.

public Coffee brewCoffee(CoffeeSelection selection) throws CoffeeException {
    switch (selection) {
        case FILTER_COFFEE:
            return brewFilterCoffee();
        default:
            throw new CoffeeException("CoffeeSelection [" + selection + "] not supported!");
    }
}

I override that method in the PremiumCoffeeMachine class to add support for the CoffeeSelection.ESPRESSO. As you can see in the code snippet, the super keyword is very helpful if you override a method. The brewCoffee method of the BasicCoffeeMachine already handles the CoffeeSelection.FILTER_COFFEE and throws a CoffeeException for unsupported CoffeeSelection s.

I can reuse that in my new brewCoffee method. Instead of reimplementing the same logic, I just check if the CoffeeSelection is ESPRESSO. If that's not the case, I use the super keyword to call the brewCoffee method of the superclass.

public Coffee brewCoffee(CoffeeSelection selection) throws CoffeeException {
    if (selection == CoffeeSelection.ESPRESSO) {
        return brewEspresso();
    } else {
       return super.brewCoffee(selection);
    }
}

Prevent a method from being overridden

If you want to make sure that no subclass can change the implementation of a method, you can declare it to be final. In this post's example, I did that for the addBeans method of the BasicCoffeeMachine class.

public final void addBeans(CoffeeSelection sel, CoffeeBean newBeans)
    throws CoffeeException {
    CoffeeBean existingBeans = this.beans.get(sel);

    if (existingBeans != null) {
        if (existingBeans.getName().equals(newBeans.getName())) {
            existingBeans.setQuantity(
                existingBeans.getQuantity() + newBeans.getQuantity());
        } else {
            throw new CoffeeException(
                "Only one kind of beans supported for each CoffeeSelection.");
        }
    } else {
        this.beans.put(sel, newBeans);
    }
}

It's often a good idea to make all methods final that are called by a constructor. It prevents any subclass from, often unintentionally, changing the behavior of the constructor.

A subclass is also of the type of its superclass

A subclass not only inherits the attributes and methods of the superclass, but it also inherits the types of the superclass. In the example, the BasicCoffeeMachine is of type BasicCoffeeMachine and Object. And a PremiumCoffeeMachine object is of the types PremiumCoffeeMachine, BasicCoffeeMachine, and Object.

Due to this, you can cast a PremiumCoffeeMachine object to type BasicCoffeeMachine.

BasicCoffeeMachinee coffeeMachine =
    (BasicCoffeeMachine) PremiumCoffeeMachine(beans);

That enables you to write code that uses the superclass and execute it with all subclasses.

public void makeCoffee() throws CoffeeException {
    BasicCoffeeMachine coffeeMachine = createCoffeeMachine();
    coffeeMachine.brewCoffee(CoffeeSelection.ESPRESSO);
}

private BasicCoffeeMachine createCoffeeMachine() {
    // create a Map of available coffee beans
    Map<CoffeeSelection, CoffeeBean> beans =
        new HashMap<CoffeeSelection, CoffeeBean>();

    beans.put(CoffeeSelection.ESPRESSO,
        new CoffeeBean("My favorite espresso bean", 1000));

    beans.put(CoffeeSelection.FILTER_COFFEE,
        new CoffeeBean("My favorite filter coffee bean", 1000));

    // instantiate a new CoffeeMachine object
    return new PremiumCoffeeMachine(beans);
}

In this example, the code of the createCoffeeMachine method returns and the makeCoffee method uses the BasicCoffeeMachine class. But the createCoffeeMachine method instantiates a new PremiumCoffeeMachine object. When it gets returned by the method, the object is automatically cast to BasicCoffeeMachine and the code can call all public methods of the BasicCoffeeMachine class.

The coffeeMachine object gets cast to BasicCoffeeMachine, but it's still a PremiumCoffeeMachine. So when the makeCoffee method calls the brewCoffee method, it calls the overridden method on the PremiumCoffeeMachine class.

Defining abstract classes

Abstract classes are different than the other classes that we've talked about. They can be extended, but not instantiated. That makes them ideal to represent conceptual generalizations that don't exist in your specific domain, but enable you to reuse parts of your code.

You use the keyword abstract to declare a class or method to be abstract. An abstract class doesn't need to contain any abstract methods. But an abstract method needs to be declared by an abstract class.

Let's refactor the coffee machine example and introduce the AbstractCoffeeMachine class as the superclass of the BasicCoffeeMachine class. I declare that class as abstract and define the abstract brewCoffee method.

public abstract class AbstractCoffeeMachine {
    protected Map<CoffeeSelection, Configuration> configMap;

    public AbstractCoffeeMachine() {
        this.configMap = new HashMap<CoffeeSelection, Configuration>();
    }

    public abstract Coffee brewCoffee(CoffeeSelection selection) throws CoffeeException;
}

As you can see, I don't provide the body of the abstract brewCoffee method. I just declare it as I would do in an interface. When you extend the AbstractCoffeeMachine class, you will need to define the subclass as abstract, or override the brewCoffee method to implement the method body.

I do some minor changes to the BasicCoffeeMachine class. It now extends the AbstractCoffeeMachine class, and the already existing brewCoffee method overrides the abstract method of the superclass.

public class BasicCoffeeMachine extends AbstractCoffeeMachine {

    public BasicCoffeeMachine(Map<CoffeeSelection, CoffeeBean> beans) {
        super();
        this.beans = beans;
        this.grinder = new Grinder();
        this.brewingUnit = new BrewingUnit();

        this.configMap.put(
           CoffeeSelection.FILTER_COFFEE, new Configuration(30, 480));
    }

    public Coffee brewCoffee(CoffeeSelection selection) throws CoffeeException {
        switch (selection) {
            case FILTER_COFFEE:
                return brewFilterCoffee();
            default:
                throw new CoffeeException("CoffeeSelection [" + selection + "] not supported!");
        }
    }

    // ....
}

Another thing I changed is the constructor of the BasicCoffeeMachine class. It now calls the constructor of the superclass and adds a key-value pair to the configMap attribute without instantiating the Map. It is defined and instantiated by the abstract superclass and can be used in all subclasses.

This is one of the main differences between an abstract superclass and an interface. The abstract class not only allows you to declare methods, but you can also define attributes that are not static and final.

Summary

As you've seen, inheritance is a powerful concept that enables you to implement a subclass that extends a superclass. By doing that, the subclass inherits all protected and public attributes and methods, and the types of the superclass. You can then use the inherited attributes of the superclass, use or override the inherited methods, and cast the subclass to any type of its superclass.

You can use an abstract class to define a general abstraction that can't be instantiated. Within that class, you can declare abstract methods that need to be overridden by non-abstract subclasses. That is often used if the implementation of that method is specific for each subclass, but you want to define a general API for all classes of the hierarchy.

# data[].attributes.attachment_link.title
OOP Concept for Beginners: What is Inheritance? - Stackify

# data[].attributes.attachment_link.description
Learn how to use Inheritance to declare different kinds of exceptions, add custom logic to existing frameworks and map your domain model to a database.

# data[].attributes.body
Un tutorial paso a paso que cubre los fundamentos del polimorfismo con ejemplos prácticos.

# data[].attributes.attachment_link.readable_text
The word polymorphism means having many forms. In simple words, we can define Java Polymorphism as the ability of a message to be displayed in more than one form. In this article, we will learn what is polymorphism and it's type.

Real-life Illustration of Polymorphism in Java: A person at the same time can have different characteristics. Like a man at the same time is a father, a husband, and an employee. So the same person possesses different behaviors in different situations. This is called polymorphism.

What is Polymorphism in Java?

Polymorphism is considered one of the important features of Object-Oriented Programming. Polymorphism allows us to perform a single action in different ways. In other words, polymorphism allows you to define one interface and have multiple implementations. The word "poly" means many and "morphs" means forms, So it means many forms.

Types of Java Polymorphism

In Java Polymorphism is mainly divided into two types:

Compile-Time Polymorphism in Java

It is also known as static polymorphism. This type of polymorphism is achieved by function overloading or operator overloading.

Note: But Java doesn't support the Operator Overloading.

Method Overloading

When there are multiple functions with the same name but different parameters then these functions are said to be overloaded. Functions can be overloaded by changes in the number of arguments or/and a change in the type of arguments.
Example 1: Example 2:
Subtypes of Compile-time Polymorphism

1. Function Overloading

It is a feature in C++ where multiple functions can have the same name but with different parameter lists. The compiler will decide which function to call based on the number and types of arguments passed to the function.

2. Operator Overloading

It is a feature in C++ where the operators such as +, -, *, etc. can be given additional meanings when applied to user-defined data types.

3. Template

it is a powerful feature in C++ that allows us to write generic functions and classes. A template is a blueprint for creating a family of functions or classes.

It is also known as Dynamic Method Dispatch. It is a process in which a function call to the overridden method is resolved at Runtime. This type of polymorphism is achieved by Method Overriding. Method overriding, on the other hand, occurs when a derived class has a definition for one of the member functions of the base class. That base function is said to be overridden.
Example
Output

subclass1
subclass2

Explanation of the above code:

Here in this program, When an object of a child class is created, then the method inside the child class is called. This is because The method in the parent class is overridden by the child class. Since The method is overridden, This method has more priority than the parent method inside the child class. So, the body inside the child class is executed.

Subtype of Run-time Polymorphism

i. Virtual functions

It allows an object of a derived class to behave as if it were an object of the base class. The derived class can override the virtual function of the base class to provide its own implementation. The function call is resolved at runtime, depending on the actual type of the object.
Diagram -
Polymorphism in Java is a concept that allows objects of different classes to be treated as objects of a common class. It enables objects to behave differently based on their specific class type.

Advantages of Polymorphism in Java

1. Increases code reusability by allowing objects of different classes to be treated as objects of a common class.

2. Improves readability and maintainability of code by reducing the amount of code that needs to be written and maintained.

3. Supports dynamic binding, enabling the correct method to be called at runtime, based on the actual class of the object.

4. Enables objects to be treated as a single type, making it easier to write generic code that can handle objects of different types.

Disadvantages of Polymorphism in Java

1. Can make it more difficult to understand the behavior of an object, especially if the code is complex.

2. This may lead to performance issues, as polymorphic behavior may require additional computations at runtime.

# data[].attributes.attachment_link.description
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

# data[].attributes.body
Este video explica cómo utilizar la herencia y el polimorfismo en Java con ejemplos claros y concisos.

# data[].attributes.attachment_link.title
Inheritance and Polymorphism in Java  - Programming Training

# data[].attributes.headline
Libro: Programación Orientada a Objetos con C++

# data[].attributes.subject
Libro: Programación Orientada a Objetos con C++

# data[].attributes.body
Un libro completo que aborda la herencia y el polimorfismo en C++ con numerosos ejemplos y prácticas recomendadas.