Polymorphism

We already know that polymorphism means different forms. But what does it mean to us?

Boiled down to its simplest definition, polymorphism is: any subclass can be used as part of the code that uses the super class.

This means we can write code that is simpler and easier to understand and also easier to modify or change.

Also, we can write code for the super class and rely on the fact that no matter how many times it is subclassed, within certain parameters, the code will still work.

Let's discuss an example.

Suppose we want to use polymorphism to help write a zoo management app. We will probably want to have a method like feed. We will also probably want to pass a reference to the animal to be fed into the feed method. This might seem like we need to write a feed method for each and every type of Animal.

However, we can write polymorphic methods with polymorphic return types and arguments:

Animal feed(Animal animalToFeed){
  // Feed any animal here
  return animalToFeed;
}

The preceding method has Animal as a parameter, meaning that any object that is built from a class that extends Animal can be passed into it. And as you can see in the preceding code, the method also returns Animal, which has exactly the same benefits.

There is a small gotcha with polymorphic return types, and that is why we need to be aware of what is being returned and make it explicit in the code that calls the method.

For example, we could handle Elephant being passed into the feed method like this:

someElephant = (Elephant) feed(someElephant);

Notice the highlighted (Elephant) in the previous code. This makes it clear that we want Elephant from the returned Animal. This is called casting. We will use casting with methods from the Android API in the next chapter and throughout the rest of the book, when we look at how to interact with our UI from our Java code.

So, you can even write code today and make another subclass in a week, month, or year, and the very same methods and data structures will still work.

Also, we can enforce upon our subclasses a set of rules as to what they can and cannot do, as well as how they do it. So, good design in one stage can influence it at other stages.

But will we ever really want to instantiate an actual Animal?

Abstract classes

An abstract class is a class that cannot be instantiated and therefore cannot be made into an object. So, it's a blueprint that will never be used, then? But that's like paying an architect to design your home and then never building it! You might be saying to yourself, "I kind of got the idea of an abstract method, but abstract classes are just silly."

If we, or the designer of a class, wants to force us to inherit before we use their class, they can declare a class abstract. Then, we cannot make an object from it; therefore, we must extend it first and make an object from the subclass.

We can also declare a method abstract and then that method must be overridden in any class that extends the class with the abstract method.

Let's look at an example; it will help. We make a class abstract by declaring it with the abstract keyword, like this:

abstract class someClass{
  /*
    All methods and variables here.
    As usual!
    Just don't try and make 
    an object out of me!
  */
}

Yes, but why?

Sometimes, we want a class that can be used as a polymorphic type, but we need to guarantee it can never be used as an object. For example, Animal doesn't really make sense on its own.

We don't talk about animals; we talk about types of animals. We don't say, "ooh, look at that lovely, fluffy, white animal!" Or, "yesterday we went to the pet shop and got an animal and an animal bed." It's just too, well, abstract.

So, an abstract class is kind of like a template to be used by any class that extends it (inherits from it).

We might want a Worker class, for example, and extend it to make, Miner, Steelworker, OfficeWorker, and, of course, Programmer. But what exactly does a plain Worker do? Why would we ever want to instantiate one?

The answer is we wouldn't want to instantiate one, but we might want to use it as a polymorphic type so we can pass multiple worker subclasses between methods and have data structures that can hold all types of Workers.

We call this type of class an abstract class, and when a class has even one abstract method, it must be declared abstract itself. And all abstract methods must be overridden by any class that extends it. This means that the abstract class can provide some of the common functionality that would be available in all its subclasses. For example, the Worker class might have the height, weight, and age member variables.

It might have the getPayCheck method, which is not abstract and is the same in all the subclasses, but a doWork method instead, which is abstract and must be overridden, because all the different types of worker doWork very differently.

This leads us neatly to another area of polymorphism that is going to make life easier for us throughout this book.

Interfaces

An interface is like a class. Phew! Nothing complicated here, then. But it's like a class that is always abstract and with only abstract methods.

We can think of an interface as an entirely abstract class with all its methods abstract and no member variables either. OK, so you can just about wrap your head around an abstract class because at least it can pass on some functionality in its methods that are not abstract and serve as a polymorphic type.

But seriously, this interface seems a bit pointless. Let's look at the simplest possible generic example of an interface, and then we can discuss it further.

To define an interface, we type:

public interface myInterface{
  void someAbstractMethod();
  // omg I've got no body
  
  int anotherAbstractMethod();
  // Ahh! Me too

  // Interface methods are always abstract and public implicitly 
  // but we could make it explicit if we prefer

  public abstract explicitlyAbstractAndPublicMethod();
  // still no body though
  

}

The methods of an interface have no body because they are abstract, but they can still have return types and parameters, or not.

To use an interface, we use the implements keyword after the class declaration:

public class someClass implements someInterface{

  // class stuff here

  /* 
    Better implement the methods of the interface 
    or we will have errors.
    And nothing will work
  */
  
  public void someAbstractMethod(){
    // code here if you like 
    // but just an empty implementation will do
  }

  public int anotherAbstractMethod(){
    // code here if you like 
    // but just an empty implementation will do

    // Must have a return type though 
    // as that is part of the contract
    return 1;  
  }
}

This enables us to use polymorphism with multiple different objects that are from completely unrelated inheritance hierarchies. As long as a class implements an interface, the whole thing can be passed along or used as if it is that thing, because it is that thing. It is polymorphic (many things).

We can even have a class implement multiple different interfaces at the same time. Just add a comma between each interface and list them after the implements keyword. Just be sure to implement all the necessary methods.

In this book, we will use the interfaces of the Android API a lot more frequently than we write our own. In the next chapter, one such interface we will use in the Java Meet UI mini app is the OnClickListener interface.

Anything might like to know when it is being clicked, perhaps a Button or a TextView widget and so on. So, using an interface, we don't need different methods for every type of UI element we might like to click.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.109.151