Sei sulla pagina 1di 57

Java with Pokemons

Object Oriented
Programming
- J Ajendra

First Edition.
Could very well be the last.

Copyright 2016 J Ajendra

All rights reserved. Though I wonder what one would ever


achieve by copying the text from this document. Yet, for
undoubtedly imaginary legal purposes and to make this
book look a bit professional, I have decided to waste 3
minutes of my apparently pointless life, in drafting this
page.

To,
Aishwarya and Vivek
Wishing you a very happy married life!

Table of Contents
INTRODUCTION .................................................................................... 1
CLASSES AND OBJECTS ....................................................................... 2
ENCAPSULATION .................................................................................. 7
INHERITANCE ..................................................................................... 14
Protected Access Modifier .............................................................. 17
Instanceof Operator......................................................................... 22
Types of Inheritance ........................................................................ 26
Diamond Problem ........................................................................... 28
POLYMORPHISM ................................................................................. 32
IS A Relationship .......................................................................... 32
Method Overriding ......................................................................... 33
Method Overloading....................................................................... 38
Constructor Overloading ............................................................... 41
Casting .............................................................................................. 44
ABSTRACTION .................................................................................... 46
Abstract Classes ............................................................................... 46
Interfaces .......................................................................................... 49
APPENDIX A ........................................................................................ 53
Reference Type and type of an Object .......................................... 53

INTRODUCTION
Folks,

ince you have started reading this book, I take it that you know
basics of programming and stuff like function calls and loops. If
not, pick this book up after you are a bit familiar with all that. OOP is
a fascinating topic and sadly, most of the explanations and examples
available on internet are a tad boring. Trust me, I learned from those and at
time, fell asleep. So this is a humble attempt to make learning interesting.
Thanks to amazing yet a bit buggy game by Niantic, the Pokemon
craze has taken the world by storm. If by any chance, you have been leaving
under the rock and haven't heard of PokemonGo or Pokemons for that
matter, please feel free to play the game for few days. Try to watch a couple
of Pokemon episodes as well! (PS. I prefer Indigo league) Anyway, we are
about to dive into the world of OOP with the help of these imaginary
creatures.
I am taking the liberty of assuming that you are familiar with the
following concepts:
1.
2.
3.
4.
5.
6.

Basic Classes & Objects


Primitive Data Types
Constructors
Function calls
Loops
Other procedural programming concepts not related to OOP.

Also, this book covers the most fundamental topics related to OOP. Some
interesting concepts like covariant returns or Constructor chaining are
skipped due to sheer boredom and laziness on authors part.
Off we go!

CLASSES AND OBJECTS


had absolutely no intention of going over classes and objects, but lucky
for you, my cat just wont stop purring and for love of God, I cannot fall
asleep. So we will quickly rush through the basics. Since the book title claims
to be somehow related to pokemons, lets start with that. Now, what are the
things that describe a pokemon? Amongst many, some are - nick name, type,
HP, CP, height, weight, etc. Don't take my word for it - consult Pokemon Go.

Fig 1.1
Great. Now lets note down what a pokemon can do. It can go in the
Pokeball, come out of the Pokeball and attack. Yep thats it for now.
Equipped with all this information, we get an overview of a pokemon.

Fig 1.2
Ladies and gentlemen, a java code representation of the above information
is known as a Class.
In desperate attempt to make my cat quiet down, we will dedicate this
chapter to the Cat God Bastet, by using pokemon Persian in our first
example. All Hail Bastet!
public class Persian{
String nickName, type;
int HP,CP;
float height,weight;
public void comeBack(){
// come back in the pokeball
}
pubic void iChooseYou(){
3

// We know what that means


}
public void captivate(){
// Its an attack move. you better duck this one
}

Basically, a class can be defined as a template that describes state and


behavior of an object of this class. What it means is, we can create an Object
bastet from the above classPersian bastet =new Persian();

And set the following values for the object:


bastet.nickName="Her Highness";
bastet.type="Goddess";
bastet.HP=40;

And so on.
We can call the methods likebastet.comeBack();
bastet.iChooseYou();
bastet.captivate();

Objects, like bastet, have a state that is different from other objects of the
same class. For example, if we create another object of Persian classPersian thunderCat=new Persian();

And set attributes of thunderCat (completely arbitrary values of my own


choice):
thunderCat.nickName="Thunder";
thunderCat.type="Normal";
thunderCat.HP= 20;

And so on.
4

Similar to bastet object, we can call the methods on thunderCat object too.
thunderCat.comeBack();
thunderCat.iChooseYou();
thunderCat.captivate ();

The data contained by both thunderCat and bastet is different, even when
they are objects of the same class.
So basically, a class defines the attributes that an object can have and actions
it can perform, but the actual value of those attributes are set by the object
and are restricted to that object only. This allows multiple objects of the same
class to be created containing different values.

Fig 1.3
And I bet you already knew all that. Anyway, all I really wanted was to show
off my pokemons. Next up is Access Modifiers. Access Modifiers are a bunch
of keywords that can be used to restrict the access to classes, data members
(Instance variable) and member functions (methods). Each access modifier

allows an instance variable and a methods to be available in a certain scope,


as shown below -

Fig 1.4
Can you guess what will be accessible in which scope in the following code?
public class Persian {
public String nickName;
String type;
private int CP;
protected int HP;
public void setCP (int cp){
}
void setHP (int hp){
}
private int getCP ( ){
}
protected int getHP (){
}
}

I know it makes no sense to use the modifiers this way for some variables
and methods, but the point here is to understand the scope.
Also, we will be dealing with protected modifier a lot while studying
inheritance.

ENCAPSULATION

ncapsulation in Java is a mechanism of wrapping the data (variables)


and code acting on the data (methods) together as single unit. Basically,
it means we have to design our class in such a way that the only way any
other class can access our data members is using methods. And why exactly
your boss makes you do this extra and tedious work? Lets take a look.
We have two pokemons - Electabuzz (Electric) and Crabby (Water). And
these pokemons are in a very intense battle at the moment. For the sake of
simplicity, lets only consider their HP.
public class Electabuzz {
int HP;
}
public class Crabby {
int HP;
}

Being a great pokemon trainer that you are, you wrote the classes for all 151
pokemons by yourself (Kudos). And the one who wrote the code for battle
simulation is none other than your friend Bob.
Now Bob has a bone to pick with you since you stole his lunch money. So he
writes his battle simulation method code as public void battleSimulation(Electabuzz ebizz, Crabby crybaby) {
ebizz.HP = -25;
crybaby.HP = 182;
// rest of the apocalyptic code
}

Oops! Can you see the problem here? HP should range from 0 to 100, but
nothing is stopping Bob from messing up our code by setting invalid values!
So how do we make sure that other programmers who apparently couldn't
7

care less of your existence, don't mess up the code? Encapsulation to rescue!
First, lets make data member private. This will ensure that no one can
directly assign value to it. Now, we want others to be able to get the value of
data member, so we write a get<member> function and return the value.
Finally, we want to allow others to set only valid values to our data
members, so we write a set<member> function and validate the input before
setting the value. And make our getters and setters public. Sounds fun right?
Lets try it.
public class Electabuzz {
private int HP;
public int getHP(){
return HP;
}
public void getHP(int h){
if(h>=0 && h<=100)
HP=h;
}
}

There you go! You have perfectly encapsulated our dear little Electabuzz.
Oh, I almost forgot - there is another perfect lifesaving reason to encapsulate
your classes. Imagine we are still going by our previous implementation
(Silly, I know). And Bob, still pissed at you, sets a negative value to HP
variable and is laughing his heart out somewhere. Now that cute
programmer you have a crush on, Alice, is using the HP variable to do some
rocket science computations. Due to Bobs prank, the values that Alice is
computing are way out of the error margin, and she is not happy. Along with
Alice there are many more developers whose code broke thanks to your HP
value and they are out for blood. Oh and mind you, they will find your
address and hunt you down! So to save your neck, encapsulate all your
classes and lead a stress free life!
Not to mention, once other programmers are using the method to access
variables, they dont care what you write inside the methods as long as your
8

method signature doesn't change and it returns a valid value. Hell, you
could go like public void setHP(int h){
if(h>=0 && h<=100)
HP=h*2;
}
public int getHP(){
return HP/2;
}

And no one would care. This allows you change your implementation
whenever you want, thus making your code extensible, flexible and
maintainable.
Also, if you don't want anyone to modify the value of your precious little
variable, simple don't provide the setter for it! This ensure read-only access
to that variable. Similarly, you can provide write-only access by not
providing the getter. (Though I am not sure why you would want to do that)
With encapsulation, you gain the magical ability to change your
implementation without breaking the code of others.
Now that we are here, lets jot down the benefits of encapsulation:
The fields of a class can be made read-only or write-only.

A class can have total control over what is stored in its fields.

The users of a class do not know how the class stores its data. A
class can change the data type of a field and users of the class do not
need to change any of their code.

Before we move on, take a look at the encapsulation in a nut-shell:

Fig 2.1
Finally, we are at the last point in Encapsulation. So buckle up.
public class Stats {
private int attack;
private int defense;
private int speed;
public Stats (int a, int d, int s){
attack=a; defense=d; speed=s;
}
public String toString(){
return "attack "+attack+" defense "+defense+" speed "+speed;
}
//Assume getters and setters here
}

And a properly encapsulated class 10

public class Psyduck {


private String name;
private String type;
private Stats stats;
public Psyduck(){
stats = new Stats(10,5,6);
}
// Assume getters and setters
}
public class Tester{
public static void main(String args[]){
Psyduck psy=new Psyduck();
System.out.println(psy.getStats());
}
}

We have a class Stats which defines some statistics about the pokemon.
Psyduck has an object of Stats and initializes it in constructor. The output
produced by Tester class would be - attack 10 defense 5 speed 6. So far so
good. Notice how Tester class is used getStats() method instead of directly
accessing the stats object like - psy.stats
Lets modify our Tester class a little and see what happens.
public class Tester{
public static void main(String args[]){
Psyduck psy=new Psyduck();
Stats statsObj=psy.getStats();
System.out.println(statsObj);
- Output 1
statsObj.setAttack(290878);
System.out.println(psy.getStats()); - Output 2
}
}

Output 1 prints: attack 10 defense 5 speed 6 and


Output 2 prints... wait for it attack 290878 defense 5 speed 6
11

Well, good news is that we used setAttack() method to set the value, but do
you see a big problem here?
Let me give you a hint. Its this lineStats statsObj=psy.getStats();

Figured out? Getters are supposed to provide read-only access, yet we are
able to modify the value of Psyducks stats without using setter at all! So
whats happening here exactly? If you are as confused as the poor Psyduck,
lets
take
a
look
in
heap
memory.

Fig 2.2
This statement: psy.getStats(); returns an reference to the Stats object. Even
though this is a copy of a reference, the reference itself is pointing to the
original Stats object in the heap! Hence any operations done on the object
using this reference variable, will change the original object. So our simple
encapsulation fails here. A way to deal with this is to actually create a new
Stats object having the values of Psyducks Stats, and return the reference to
this object.
Your getter for stats would look something like this.
12

public Stats getStats(){


Stats temp=new Stats(this.stats.getAttack(),this.stats.getDefense(),
this.stats.getSpeed());
return temp;
}

And in heap:

Fig 2.3
Remember this for all the getters that are returning an object reference, be it
an actual object, an array or even a StringBuffer.
Now, we are finally done with encapsulation.

13

INHERITANCE

et's take a look at some of the classes we created till now:


public class Persian{
String nickName, type;
int HP,CP;
float height, weight;
public void comeBack(){
}
pubic void iChooseYou(){
}
public void captivate(){
}
// setters and getters for all the fields.
}
public class Electabuzz{
private String nickName, type;
private int HP,CP;
private float height, weight;
public void comeBack(){
}
pubic void iChooseYou(){
}
pubic void thunderbolt(){
}
// setters and getters for all the fields.
}
public class Squirtle{
private String nickName, type;
private int HP,CP;
private float height, weight;

14

public void comeBack(){


}
pubic void iChooseYou(){
}
pubic void waterGun(){
}
// setters and getters for all the fields.
}

I know you guys are smart and you have already figured out the problem
here. But just to be on the same page, its - Code duplication. We are writing
too much code! Imagine we were to continue using this approach for all 151
pokemons in Indigo league, and then you decide to change HP from int to
float, or change the implementation of comeBack() method. We will end up
wasting next two days of our precious little life, changing all the 151 classes.
Shall we try to get rid of this problem? This is where Inheritance comes into
the picture.
So here's what we are going to do:
1. Move all the duplicate code to a common class (may be class
Pokemon?)
2. Create Pokemon specific classes such that it contains fields and
methods of the common class while implementing its specific code as
well.
When you inherit from an existing class, you can reuse methods and fields
of parent class (Pokemon), and you can add new methods and fields in the
base class (say class Pikachu?).
Moving common code to Pokemon class:
class Pokemon{
private String nickName, type;
private int HP,CP;
private float height, weight;
15

// All setters and getters


public void comeBack(){
}
pubic void iChooseYou(){
}
}

When a class Pikachu inherits from the class Pokemon, the definition of the
class Pikachu becomes:
class Pikachu extends Pokemon{
pubic void thunderbolt(){
}
}

class Pikachu extends Pokemon - what this line implies is that all the fields
and methods of pokemon class are part of Pikachu class as well and hence
they are accessible to it.

Fig 3.1
16

So if we create an object of Pikachu now, it would be:


Pikachu pika = new Pikachu();
pike.setHP(10); // inherited from pokemon
pika.comeBack(); // inherited from pokemon
pika.thunderbolt(); // attack specific to Pikachu class.

So basically, our code in Pokemon class will be reused by every other class
that extends Pokemon.
If tomorrow we decide to change the implementation comeBack() method,
all we need to do is make change in the pokemon class and everything will
be fine in our little java universe.
Inheritance is used to address two things:
1. Code reuse
2. Polymorphism
We have already dealt with code re-usability and we will take a look at
polymorphism in a while. For now, lets drill into inheritance a bit more.

Protected Access Modifier


Well, back in the Introduction chapter, I promised, against my
better judgment, that we will learn about protected access modifier in
Inheritance. Please remind me never to make any promises while drunk.
Anyhow, let's take a look at one of the most misunderstood access modifiers
in Java.

17

Fig 3.2
A protected access modifier is almost similar to default modifier. Default
member and functions are accessible in the class and Package. Since all
access modifiers are accessible in the same class, no point in making a big
fuzz about it. So for the sake of understanding, let's say that
default modifier provides package restriction. Any other class outside the
package of the current class will not be able to access anything that current
class had marked default. For the classes outside the package, all default
members and functions are considered to be private.
If you think this is confusing, then you better start praying to God Anubis as
the protected modifier is the king of confusions. But fear not, we will try to
make it as simple as possible to understand.
A default member may be accessed only if the class accessing the member
belongs to the same package, whereas a protected member can be
accessed by a subclass even if the subclass is in a different package.
What this means is, protected modifier is a bit considerate of parent-child
relationship. When a subclass is in a different package, it can access its
parent's default members and functions only through inheritance. (We will
look at this in a bit)
When you think of default access, think package restriction. But when you
think protected, think package + children.

18

protected access modifier focuses on two factors : Packages and Subclasses


Facts about the fields or methods of a class that are marked protected are:
1. They are accessible to all classes within the same package.
2. They are accessible to all subclasses irrespective of the package of the
subclass

For example: we have package parent;


class Pokeball{
protected int catchRate;
}

// protected data member

Case 1: Any class in the same package package parent;


class CatchPokemon{
void usePokeball(){
Pokeball p=new Pokeball();
System.out.println(p.catchRate);
}
}

Since classes Pokeball and CatchPokemon are in the same package, we can
create an object of Pokeball and access catchRate data member.
Case 2: Any Class in different package
package child;
class GreatBall {
void setCatchRate(int cr){
Pokeball p=new Pokeball();
p.catchRate=cr;
// compiler cant find catchRate.
19

}
}

Since classes Pokeball and CatchPokemon are in the different package,


catchRate acts as a private member for GreatBall and hence cannot be
accessed.
Case 3: Any Class in different package that extends from Pokeball
package child;
class UltraBall extends Pokeball{
void setCatchRate(int cr){
catchRate=cr;
// Compiler doesn't even flinch.
}
}

Since UltraBall is extending from Pokeball, all data member of Pokeball


(except private) also becomes data members of UltraBall. So we can simply
access catchRate as if its a data member of UltraBall. So far so good. But
what happens when we do package child;
class UltraBall extends Pokeball{
void setCatchRate(int cr){
catchRate=cr;
//all good - inherits from parent
Pokeball p=new Pokeball()
p.catchRate=cr;
// Compiler is furious
}
}

Even when UltraBall inherits from Pokeball, creating an object of Pokeball


and accessing default member is a No-Go. Since creating an object and trying
to access the data member has nothing to do with inheritance, this becomes
a classic case 2.
20

Hence we said something like this before When a subclass is in a different


package, it can access its parent's default members and functions only
through inheritance. Hopefully its clear now. If not, feel free
to perform black magic on the kind folks at Sun Oracle.
Just one last point before I wrap this up. Consider the following piece of
code.
package parent;
class Pokeball{
protected int catchRate;
}

// protected data member

package child;
class UltraBall extends Pokeball{
public int size;
void setCatchRate(int cr){
catchRate=cr;
// inherits from parent
}
}

Now, UltraBall class has two data members - size and catchRate (Inherited
from Pokeball)
class CatchPokemon{
void usePokeball(){
UltraBall ub=new UltraBall ();
System.out.println(ub.size);

// Works perfectly as size is public


member of UltraBall
System.out.println(ub.catchRate); // And the great compiler is
displeased.
}
}

21

What happened here is - when UltraBall inherited a protected data member


(catchRate) form its parent (Pokeball), catchRate became a private data
member of UltraBall class. Hence any other class cannot use catchRate from
an object of UltraBall, unless the class extends from UltraBall. In that case,
catchRate in this new class is accessible only by inheritance (case 3) and
becomes a private data member of this new class.
Whew! That wraps up protected modifier. Lucky for you, it is used in very
special cases and you wont probably see it much.

Instanceof Operator
Before we dwell into the instanceof operator, let's first understand IS-A
relationship.
When a class inherits form other class either by extending the class or
implementing the interface (stay tuned for this one), it is said that the base
class IS-A type of Parent class. In our example:
Pikachu IS-A Pokemon as Pikachu extends Pokemon.
Pokemon IS-A Object as every class implicitly extends form Object class
Pikachu IS-A Object as Pokemon IS-A Object and Pikachu IS-A Pokemon
Note: In Java every class implicitly extends from Object class. Hence the
methods of the Object class such as equals(), notify() and others are
accessible to every other class.
IS-A relationship is a uni-directional relationship. i.e. Every object of
Pikachu IS-A Pokemon, but every Pokemon need not be Pikachu. A
Pokemon can be Onix as well right?

22

Fig 3.2
So what does this mean?
Since Pikachu IS-A Pokemon, a reference of type Pokemon can hold a
reference to Pikachu object.
Pikachu pika=new Pikachu();
Pokemon anyPoke=pika;

Woah! Let's see whats happening here. Reference type (Appendix A) of


anyPoke object is a Pokemon and it is holding a reference to Pikachu object.
Why does the compiler allow this? Well, the compiler says, since Pikachu is
extending Pokemon, all the fields and methods in Pokemon class
are definitely present in Pikachu class. So saying pika.comeBack(); and
anyPoke.comBack();

Are one and the same thing, as the comeBack() method is defined in
Pokemon class. What if we try to call the method specific to Pikachu class?
pika.thunderbolt(); // works fine

23

anyPoke.thunderbolt(); // Compiler cant find this method in Pokemon


class, so it fails to compile.

Alright, it makes sense why compiler would allow this, but why would we,
as a coder, want to do this? Let's introduce a Pokemon Trainer - Ash.
class PlayerAsh{
}

Now Ash wants to call his pikachu and charmander back class PlayerAsh{
void pikachuComeBack(Pikachu p){
p.comeBack();
}
void charmanderComeBack(Charmander c){
c.comeBack();
}
}

And if he had 10 more pokemons, we will end up writing the methods for
all pokemons. But wait, comeBack() method is a common method defined in
Pokemon Class. So it doesnt matter if we write p.comeBack();
or c.comeBack(); same code will be called. Now since both Pikachu and
Charmander IS-A Pokemon, and compiler allows us to use Pokemon
reference type to hold reference of objects of its child classes, we can rewrite
the PlayerAsh class as:
class PlayerAsk{
void pokemonComeBack(Pokemon p){
p.comeBack();
}
}

24

So irrespective of whether the pokemon is Pikachu or Charmander or Evee,


this one method works for all. Hurray for us!
Now lets say, we have an object of Charmander referred by Pokemon
reference typePokemon charmander=new Charmander();

Now, if we want to call ember() method of charmander obj, we wont be able


to do so as long as the object is referred to by Pokemon reference type.
charmander.ember(); // Compiler cant find this method in Pokemon
class, so it fails to compile.

What we can do, is cast the object back to Charmander reference type:
Charmander cd = (Charmander)charmander; // This is called as downcasting

Now cd.ember(); works like a blazing fire!


But wait, what if we are getting our Pokemon from some other code? How
are we to know that our Pokemon reference type has a Charmander object?
If its our arch enemy Bob sending us the object reference, its possible that
he has set something up to mess up our code. Say for example, Bob sends a
Pikachu object with reference type of Pokemon. Then Charmander cd = (Charmander) anyPoke; // anyPoke is a Pikachu
object
cd.ember();

The code would compile just fine, but if will burst like a volcano at runtime
throwing a ClassCastException.
25

To protect our code from such unexpected eruptions, we use an instanceof


operator.
if (anyPoke instanceof Charmander) {
Charmander cd = (Charmander)anyPoke;
cd.ember();
}

instanceof keyword is a binary operator used to test if an object (anyPoke ) is


a subtype of a given Type. instanceof operator only works for the classes in
hierarchy. anyPoke is an instance of Charmander class. So if (anyPoke
instanceof Charmander) returns true. Since Charmander class extends
Pokemon, if (anyPoke instanceof Pokemon) also returns true. But if anyPoke
is an object of Pikachu, then if (anyPoke instanceof Charmander) returns false
as Pikachu is not of the type Charmander. Remember, in inheritance, every
time we cast an object, check it using instanceof operator to avoid runtime
exceptions.

Types of Inheritance
Now that we have a basic understanding of inheritance, let's take a look at
the types of inheritance supported by Java. And this time, we will be taking
some help from Team Rocket.

1. Single Inheritance

This is your most basic inheritance and is too simple for a smart person like
you. Single inheritance means one class extending another class. By now,
you must have become an expert in this type, provided you didn't sleep

26

through the chapter. For the sake of consistency, an example would be,
Meowth extends Pokemon.

Fig 3.3

2. Multi-level Inheritance

Multi-level inheritance is the one where one class extends another which inturn extends another which in-turn can extend another and will finally give
you a headache. Following diagram will explain it better than mere words.

Fig 3.4
27

3. Hierarchical Inheritance

In such kind of inheritance one class is inherited by many sub classes. Class
Pokemon is inherited by Meowth, Ekans, Koffing etc. Go Team Rocket!

Fig 3.5

Diamond Problem
The thing is, in Object Oriented Programming, there are two more types of
inheritance. But the almighty creators of Java decided not to support them
for the reasons we will soon look into. But first let's see what these types of
inheritance are:

1. Multiple Inheritance

In this type, one class inherits from two or more classes. Simple enough? Not
when we'll understand the problems of this design.

28

Fig 3.6
We cant attempt to do this in Java, but if we were to try, code would be
something like this.
class BabyNidoran extends Nidoking, Nidoqueen{
}

2. Hybrid Inheritance
Hybrid inheritance can be created using Hierarchical and Multiple
inheritance. A base class inherits from two or more classes and those classes
inherits from the same parent class.

Fig 3.7
29

This brings us to the infamous Diamond Problem. Evidently, the above


diagram looks like a diamond, hence the name.
Consider the following code:
class Nidoking{
public void poisonSting(){
//attack take out 20 HP of the opponent
}
public void comeBack(){
// Inherited from Pokemon Class
// goes into UltraBall
}
}
class Nidoqueen{
public void poisonSting(){
//attack takes of 30 HP of the opponent
}
public void comeBack(){
// inherited from Pokemon Class
// goes into GreatBall
}
}
class BabyNidoran extends Nidoking,Nidoqueen{
}

Now BabyNidoran is inheriting a method poisonSting from Nidoking


which takes out 20 HP. But BabyNidoran is also inheriting the same method
from Nidoqueen where it takes out 30 HP. So, in the following code:
BabyNidoran bn=new BabyNidoran();
bn.poisonSting(); // Compiler cannot determine which method to call.

30

Similarly, comeBack() method, which is inherited by both Nidoking and


Nidoqueen is also indirectly inherited by BabyNidoran. Here, there will be
an ambiguity if comeBack() method is called on BabyNidoran's object.
Compiler wont be able to decide if the BabyNidoran should go into
UltraBall or GreatBall
Due to this ambiguity, multiple inheritance and hybrid inheritance is not
supported by Java.

31

POLYMORPHISM

rab a cup of coffee (or your choice of drug), because this one is going to
need your brain working at full throttle.

Polymorphism technically means having several different forms. Remember


Nymphadora Tonks from Harry Potter? A wizard who could change her
form at will. Yep, thats polymorphism. Though the term used in Harry
Potter is Metamorphmagus. Never mind that. Polymorphism for us, in Java,
is going to revolve around the methods. But for that, the necessary condition
is Inheritance. We are getting a bit ahead of ourselves. Lets refresh a few
things first.

IS A Relationship
We looked over IS-A Relationship back in Inheritance. Any class that inherits
- extends or implements (will look at this one soon) from other class satisfies
this relationship. And since all classes implicitly inherit from Object class, all
classes satisfy IS-A Relationship with Object class.

Fig 4.1
32

Here,
Pokemon IS-A Object
Bulbasaur IS-A Pokemon
Squirtle IS-A Pokemon
Pikachu IS-A Pokemon
Bulbasaur IS-A Object
Squirtle IS-A Object
Pikachu IS-A Object
And thats about it. We will use this new-age foundation knowledge to
understand the following concepts.

Method Overriding
After much deliberation and long discussions with my guide and mentor,
my Cat, I have finally decided to use a Mouse Pokemon, Pikachu, for this
topic. Here are the classes we have defined so far (For the obviously lazy
reasons, only the relevant code is written)
class Pokemon{
private String nickName, type;
private int HP,CP;
private float height, weight;
// All setters and getters
public void comeBack(){
}
pubic void iChooseYou(){
}
}
class Pikachu extends Pokemon{
pubic void thunderbolt(){
}
}
33

Alright, now according to what we studied till now, Pikachu class contains
almost (remember access modifiers?) everything present in Pokemon class.
So we can peacefully write the following code.
Pikachu pika=new Pikachu();
pika.comeBack();
//From Pokemon Class
pika.iChooseYou();
//From Pokemon Class
pika.thunderbolt();
//From Pikachu Class

For those who have seen the anime series of Pokemon (those who havent,
please see it!), you might remember that Pikachu is one stubborn Pokemon
who refuses to go in the Pokeball. For humoring you all, which seems like
my job here, lets make it so that when comeBack method is called on a object
of Pikachu class, our code should say I am the great Pikachu and no
Pokeball shall contain me.
If Pikachu wasnt inheriting from Pokemon class, our code would like:
class Pikachu{
public void comeBack(){
System.out.println(I am the great Pikachu and no Pokeball shall contain
me.);
}
pubic void thunderbolt(){
}
}

Well, even with inheritance, all we have to do is write the same code!
class Pikachu extends Pokemon{
public void comeBack(){
System.out.println(I am the great Pikachu and no Pokeball shall contain
me.);
}
pubic void thunderbolt(){
}
34

Here, we are Overriding the comeBack() method form Pokemon class in


Pikachu class. What this means is, whenever an object of Pikachu class calls
comeBack() method, the implementation in Pikachu class gets executed.
Pikachu pika=new Pikachu();
pika.comeBack();
//From Pikachu Class
pika.iChooseYou();
//Still from Pokemon Class

This will display - I am the great Pikachu and no Pokeball shall contain me.
The implementation of non-overridden methods, like iChooseYou, will
remain the same as Pokemon class implementation. So thats about it. The
only big fuzz about overriding is that it is runtime polymorphism. i.e. JVM
decides at runtime which comeBack() should be called, whether the one in
Pokemon class or the one in Pikachu class. And how does JVM decide this?
You probably guessed it, depends on the Object type. Lets take a look at
some code.
class Pokemon{
private String nickName, type;
private int HP,CP;
private float height, weight;
// All setters and getters
public void comeBack(){
System.out.println(On my way);
}
pubic void iChooseYou(){
}
}
class Pikachu extends Pokemon{
public void comeBack(){
System.out.println(I am the great Pikachu and no Pokeball shall contain
me.);
}
35

pubic void thunderbolt(){


}
}
class Charmander extends Pokemon{
pubic void ember(){
}
}
Pokemon poke=new Pokemon();
poke.comeBack(); // On my way
Pikachu pika=new Pikachu();
pika.comeBack(); //- I am the great Pikachu
and no Pokeball shall contain me.
Charmander charu=new Charmander();
charu.comeBack();// On my way

Ok, poke object executes comeBack() implementation of pokemon class, and


so does the charu object. But since Pikachu class has overridden the
comeBack() method, pika object executes the overridden method in Pikachu
class. So far so good. Problem starts here.
Going back to IS-A relationship, we know that Pikachu IS-A Pokemon. So
reference type of Pokemon can refer to a Pikachu object. Consider the
following code.
Pikachu pika=new Pikachu();
Pokemon poke=pika;

Perfectly fine code, thanks to Inheritance. Now lets see what complier
thinks.
Complier says, since Pikachu inherits from Pokemon, all the methods and
data members of Pokemon are accessible in Pikachu. So reference type of
36

Pokemon can refer to Pikachus object as long as the methods or fields


accessed by this object reference are existing in Pokemon class. Too big
sentence. Lets break it down. As far as compiler is concerned, if the reference
type is pokemon, then at compile time, it can only access the methods / data
members present in Pokemon class. So saying:
Pikachu pika=new Pikachu();
Pokemon poke=pika;
poke.thunderbolt(); // not going to work

Since Pokemon class does not contain thunderbolt() method, compiler wont
let you compile the above code.
But saying:
poke.comeBack();

is perfectly acceptable as Pokemon class contains comeBack() method. But


can you guess the output of the above code?
Its - I am the great Pikachu and no Pokeball shall contain me.
Weird? What is happening here is, at compile time, compiler makes sure
that comeBack() method is present in Pokemon class even though poke refers
to Pikachus object. Compiler couldnt care whether poke is referring to
Pikachus object or Charmanders object, as long they as satisfy IS-A
relationship.
But at runtime, the JVM sees that even though poke is of type Pokemon, it is
referring to Pikachus object, so JVM executes the comeBack() method
overridden in Pikachu Class. Hence the runtime polymorphism.

37

Fig 4.2
Wait, what if we want to call the parents method from the overridden
method? Just use super.methodName(); For example:
class Pikachu extends Pokemon{
//overridden method
public void comeBack(){
super.comeBack(); // calls Pokemon Classs comeBack method.
}
pubic void thunderbolt(){
}
}

Finally! That was a big one. Take a short break and digest what the hell we
just studied. Done? Now, Advance soldier!

Method Overloading
Compared to method overriding, this is going to be a walk in a park. One
thing to remember is, for method overriding, Inheritance is a necessity, but
for overloading, such is not a case. Also, Overloading is compile time
polymorphism. i.e. compiler determines which method will be called at

38

compile time itself. In overriding, JVM determines which method will be


called at run time (hope you remember).
To understand this concept. We are going to look at evolutions in Pokemon
series (Not PokemonGo). Remember how pokemons used to evolve? It
would depend on their battle experience and wait for it, stones!
Consider dear little Eevee. It can evolve depending on the environment or
by being exposed to stones. Now, if we were to write an evolve() method in
our Eevee class, should we be writing two methods like evolve() and
evolveUsingStone()? I guess not. We would rather overload the evolve()
method.
Heres how it works:
class Eevee extends Pokemon{
public void evolve(){
// natural evolution
}
public void evolve(Stone stone){
//evolution by stone
}
}

If you pay a tinee - tiny attention, you would notice that method name here
is same evolve(). What differs is parameters.
Eevee vee=new Eevee();
vee.evolve(); // natural evolution
vee.evolve(waterStone); // stone evolution

An overloaded method have different signatures. Here signature means


parameters or their sequence. Return type of a method is not included in
method signature.
At compile time, compiler determines which method should be called
depending on the method signature. Hence this is known as Compile time
Polymorphism. There are reasons why things are the way they are, like why
39

return types are not included in method signature. I would love to discuss
that but I am low on caffeine and it would be a great exercise for you to go
and look it up on internet.
In the beginning, I said that overloading does not need inheritance, but what
if there is inheritance? Lets say for arguments sake, that all pokemons can
naturally evolve. We know thats not true, but bear with me for a while. Since
all pokemons can evolve, lets put the natural evolution code in Pokemon
class.
class Pokemon{
private String nickName, type;
private int HP,CP;
private float height, weight;
// All setters and getters
public void comeBack(){
}
pubic void iChooseYou(){
}
pubic void evolve(){
// Natural evolution
}
}

Now in Eevee class, no need to write the code for natural evolution as it
inherits the method from Pokemon class.
class Eevee extends Pokemon{
public void evolve(Stone stone){
//evolution by stone
}
}

40

Even in this case, what we have is method overloading. Method evolve() in


Pokemon class is overloaded by method evolve(Stone stone) in Eevee Class.
So the following code is still valid:
Eevee vee=new Eevee();
vee.evolve(); // natural evolution
vee.evolve(waterStone); // stone evolution

This wraps up method overloading.

Constructor Overloading
Lets say we created our pikachu object:
Pikachu pika = new Pikachu();

Now we want to set the fields:


pika.setHP(10);
pika.setType("Electric");
pika.setHeight(3.2);

And so on.
Imagine, we need to create 10 pikachu objects and set values for every field.
Number of fields that we have defined so far are - 6. So total number of lines
we need to write to achieve this are: 6*10 = 600. Coding this way is a sureshot one way ticket to getting kicked out of your company. Constructors to
your rescue.
Constructors are the piece of code that are responsible to create an object on
the heap and assign values to instance variable.
They are very similar to a method in a class with 2 specifications 1. There is absolutely no return type - not even void.
41

2. The name of the constructor is same as the class name.


Whenever obj=new Pikachu(); is executed, a Pikachu's constructor is called.
They can be default or parameterized. (Discussed ahead)
But wait, we didn't write a constructor for any of the classes before yet we
were able to create their objects. This is because, if there is no (almost)
constructor in the class, compiler adds one on its own.
So for our Pikachu class, the compiler added constructor would be:
class Pikachu extends Pokemon{
Pikachu(){
// default Constructor
}
pubic void thunderbolt(){
}
}

Default constructors sets the instance variables to their default values. So any
int field will be 0, String will be null and so on.
A parameterized constructor is one which takes values in the parameters
and assigns them to the instance variables.
class Pikachu extends Pokemon{
Pikachu( int hp,int cp, String nickname,String type, float height,float
weight){
setHP(hp);
setCP(cp);
setNickName(nickname);
setType(type);
setHeight(height);
setWeight(weight);
}
pubic void thunderbolt(){
42

}
}

Since we have already implemented setters (encapsulation, remember?),


lets just use those to set the values. So far so good. Now we can create a
Pikachu object as:
Pikachu pika=new Pikachu(10,15,"Pika","Electric",3.2,4.1);

Need another object?


Pikachu pika1=new Pikachu(12,10,"Pika1","Electric",3.8,4.5);

If you noticed, this takes care of our 600 lines code problem. No need to
explicitly call setters anymore. Now you rock in your job.
But what if you ended up doing something like thisPikachu pika2=new Pikachu(); // Compiler cries like an irritated baby

If we only have parameterized constructor in the class, this line can give you
nightmares. What happened to compiler adding default constructor? You
see, compiler adds default constructor if and only if there is no other
constructor defined. Since we have already defined a parametrized
constructor, compiler wont add a default one and the above line of code will
fail. In most cases, this is a required behavior as we dont want anyone to
create new Pikachu object without specifying the values for the fields, but if
we do want to allow such initialization, for whatever reason, simply add a
default constructor. So our Pikachu class becomes:
class Pikachu extends Pokemon{
Pikachu(){
}
Pikachu( int hp,int cp, String nickname,String type, float height,float
weight){
// parameterized constructor.
43

setHP(hp);
setCP(cp);
setNickName(nickname);
setType(type);
setHeight(height);
setWeight(weight);
}
pubic void thunderbolt(){
}
}

And now you can sleep peacefully. This is called as constructor overloading.

Casting
A couple of pages back, we looked at this piece of code
Pikachu pika=new Pikachu();
Pokemon poke=pika;
poke.thunderbolt(); // not going to work

And quoted Since Pokemon class does not contain thunderbolt() method,
compiler wont let you compile the above code.
But hey, poke is definitely referring to object of Pikachu, so the object must
be capable of executing thunderbolt() method. The compile time check is
preventing us from executing - poke.thunderbolt();
So, we cast the object.
There are two types of casting
Up - Casting
An object is up-casted when it is assigned to the reference type of its classs
parent.
Pikachu pika=new Pikachu();
Pokemon poke=pika;
44

Here, object pika is assigned to Pokemon reference type. Remember,


Pokemon class is a parent of Pikachu class. This casting is done implicitly
and thus requires no additional code. Plain and simple. However, Down
Casting is more fun.
Down Casting
Down casting will help us solve the problem we faced while executing the
code - poke.thunderbolt();
And lucky for you, we have already looked at this one in Inheritance
chapter. So just to re-cap - we assign an object with a reference type of
parent class to its respective object type. Except, this has to be done
explicitly.
Pikachu pika=(Pikachu)poke;
pika.thunderbolt();

Or if you are being really lazy


((Pikachu)poke).thunderbolt();

Alright, we will stop with polymorphism. If you have somehow


understood till here, next part will be a walk in a park.

45

ABSTRACTION
Abstract Classes
For a while now, we have been slowly creating a class design while learning
the OOP concepts. Lets take a look at what we have done so far.

Fig 5.1
But there is a problem with this design.
Bulbasaur bulbasaur=new Bulbasaur();
Squirtle squirtle =new Squirtle();
Pikachu pikachu =new Pikachu();

This code makes sense. We have few pokemons Bulbasaur, Squirtle and
pikachu. But what about this code?
Pokemon pokemon = new Pokemon();

Though valid, this code doesnt make any sense as there is no Pokemon
called a Pokemon. We shouldnt be able to have an object of type Pokemon
because, hey, such pokemon cannot exist. So we mark the class as Abstract
class. Abstract classes cannot be instantiated and are only useful as parent
classes in inheritance. Seems like the kind of thing we want.
abstract class Pokemon{
private String nickName, type;
46

private int HP,CP;


private float height, weight;
// All setters and getters
public void comeBack(){
}
pubic void iChooseYou(){
}
}

The other non-abstract classes which inherit from this class are called as
Concrete classes. So all those 151 pokemon classes that you spent a night
writing, are concrete classes. Thanks to making your Pokemon class abstract,
no other developer, especially Bob, can instantiate it. But reference type of
Pokemon can still be used to point to the objects of its child type.
Pokemon pokemon = new Pokemon(); // Not valid
Pokemon squirtle = new Squirtle(); // works just fine.

Back when we were learning method overloading, and added evolve


method in Pokemon Class, it was probably not the best thing to do, since all
pokemons dont evolve. But guess what, many of them do evolve and
writing the evolve() method in each of those evolving pokemon class is a tad
bit expensive, time consuming, redundant and literally boring. So we create
a new class
abstract class EvolvingPokemon extends Pokemon{
public void evolve(){
}
}

And make all those evolving pokemon classes extend EvolvingPokemon


class instead of Pokemon class. Since EvolvingPokemon is extending from
Pokemon class, all fields and methods of Pokemon class are part of
EvolvingPokemon class and will also be part of its child classes.
class Eevee extends EvolvingPokemon {
public void evolve(){
}
}
47

class Pikachu extends EvolvingPokemon {


public void evolve(){
}
}
class Onix extends Pokemon {
// no evolve method
}

Right now, our class design would be

Fig 5.2
Pokemon and EvolvingPokemon are abstract classes.
We can write an implementation of evolve method in EvolvingPokemon
class and it would be a default behavior for each pokemon that extends this
class. But what if, we want to force all classes to write their own
implementation of evolve method? We can make the method abstract.
abstract class EvolvingPokemon extends Pokemon {
public abstract void evolve();
}

An abstract method does not have any implementation. And remember, any
class that has an abstract method, must be declared abstract as well. i.e. only
abstract classes can have abstract methods.
48

Also, only a concrete class has to implement all abstract methods. An


abstract class that inherits from other abstract class, like EvolvingPokemon
inheriting from Pokemon, need not implement the abstract methods in
Pokemon class.

Interfaces
Spoiler alert a bit of theory ahead. Interfaces are abstract classes on steroids
(or marijuana). Remember we could define data members and method
implementations for non-abstract methods in abstract classes? The only
thing you can do with interface is define abstract methods and constants. All
methods in interface are implicitly public.
So why do we need interfaces? They are basically a workaround for a
multiple inheritance problem. But heres a catch. An interface is nothing
more than a contract a contract that says, any class implementing the
interface, must implement all the methods defined in the interface. Similar
to abstract methods in abstract classes.
Lets say we want to enforce the following conditions on all Pokemons. All
water-type pokemons should have splash attack, all fire-type should have
ember, electric-type should have thunderbolt and so on. We can create type
interfaces and make pokemons implement their respective types.
interface WaterType {
public void splash();
}
interface FireType {
public void ember();
}
interface ElectricType {
public void thunderbolt();
}
class Squirtle extends EvolvingPokemon implements WaterType{
49

public void evolve(){


// from EvolvingPokemon class
}
public void splash(){
// from interface
}
}
class Charizard extends Pokemon implements FireType{
public void ember(){
// from interface
}
}

Fig 5.3
What if a pokemon has more than one type? If type were classes, we wont be
able to inherit from multiple type classes, but we can implement multiple
interfaces.
interface FlyingType {
public void wingAttack();
}
interface PoisonType {
50

public void sting();


}
class Zobat extends EvolvingPokemon implements FlyingType,
PoisonType {
public void wingAttack (){
// from Flyingtype interface
}
public void sting (){
// from PoisonType interface
}
}

So thats how we can deal with multiple inheritance. Though technically,


interfaces cannot be considered as inheritance since all they do is enforce a
contract and not does not provide the implementing class with any
implemented methods or data members.
Also, interfaces can inherit from other interfaces
interface GenerationOneTypes {
}
interface PoisonType extends GenerationOneTypes {
public void sting();
}

Just like inheritance, classes implementing interfaces also are in a IS-A


relationship. So, we can still use instanceof operator and all other features of
inheritance are supported. For e.g. we can use a reference type of interface
to hold a Pokemon type object.
FlyingType pokemon=new Pidgey();
pokemon.wingAttack(); // works
pokemon.evolve(); // cannot find method

51

And we are done with Abstraction, though it was a bit hastily. There are
few more topics that can be discussed in OOP such as Object Composition
and cohesion-coupling, but Ill stop troubling you here.

52

APPENDIX A
Reference Type and type of an Object
This ones a quickie. A reference type of any object is the class name used in
object declaration.
Pokemon odd;

Here, the object reference is - odd while reference type of the object is Pokemon.

The type of an object is the one that is used in Object initialization.


odd = new Oddish();

The Object is of type Oddish, while the object is referred to by a reference of


type Pokemon.
If you are wondering how this is possible, it will make more sense after you
study Inheritance and Polymorphism.

53

Potrebbero piacerti anche