Object Orientation
Encapsulation
Do not expose class variables, instead of doing this, use setter and getter methods and keep class variables private.
public class Car { private int price; private int maxSpeed; public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } }
What is the advantage of previous usage, first of all flexibility. For example you have changed your mind, decide to keep max speed read only. So we can just remove setMaxSpeed method or change it to private for internal use.
Another advantage is validation, if user want to set negative value for car price, so you can add a validation in setPrice that is it.
Is-A and Has-A Relationship
So, Ferrari is a Car, Cow is an animal lets codify these statements.
public class Car{} public class Ferrari extends Car{}
public class Animal{} public class Cow extends Animal{}
Water is drinkable
public interface Drinkable{ public void drink(); } public class Water implements Drinkable{ public void drink(){} }
Car has tires.
public class Tire{} public class Car{ Tire tires[]; }
Polymorphism
If an object can pass more than one is-a (instance of) test, it is polymorphic.
public class Bat extends Bird,Mammal { //False a class can only extend one class. }
Some languages like C++ supports multiple inheritance, but sometimes multiple inheritance causes confusion. For example both Bird and Mammal have giveBirth() method, when we call giveBirth in Bat class, which giveBirth will work ? Will bat give birth like mammals or birds. As a result Java does not support multiple inheritance to prevent this confusion.
A proper structure could be like that
public class Bat extends Bird implements Mammal { }
So, Bat is an object
Bat is a bird
Bat is a mammal.
It’s a Bird…It’s a Plane…It’s Superman
public interface Flyable{ public void fly(); } public class Bird implements Flyable { public void fly(){} } public class Plane implements Flyable { public void fly(){} } public class Superman implements Flyable { public void fly(){ } }
Look at the following code
public interface Playable { public void play(); } public class Player implements Playable { public void play() { System.out.println("I am a player"); } } public class FootballPlayer extends Player implements Playable{ @Override public void play() { System.out.println("I am football player"); } public static void main(String args[]){ FootballPlayer footballPlayer = new FootballPlayer(); Playable playable = footballPlayer; Player player = footballPlayer; footballPlayer.play(); playable.play(); player.play(); } }
Output is :
I am football player
I am football player
I am football player
We have called play method on three different types but results are same, because actual object behind the instance is important, football player, player and playable are all in different types but actual object behind the types is FootballPlayer object.
Overriding / Overloading
If you want to change behavior of subclass you can use overriding. We override play method in the following example. Player is more general it says “I am a player” but FootballPlayer is more specific, and it says “I am a football player”.
public class Player { public void play() { System.out.println("I am a player"); } } public class FootballPlayer extends Player{ public void play() { System.out.println("I am a football player"); } public void kickTheBall(){ System.out.println("I kick the ball"); } }
In abstract classes you have to override abstract methods, but while extending concrete classes you do not have to override.
Player player = new Player(); Player footballPlayer = new FootballPlayer(); player.play(); footballPlayer.play(); player.kickTheBall(); // illegal,compiler error footballPlayer.kickTheBall(); // illegal, compiler error
Output is:
I am a player
I am a football player
What about this code, does it compile ?
public class Player { public void play() { System.out.println("I am a player"); } } public class FootballPlayer extends Player{ private void play() { System.out.println("I am a football player"); } }
No it does not compile, because FootballPlayer’s play method is private. If you override a method in a subclass you cannot be more restrictive.
| Player.play() | FootballPlayer.play() | Result |
| private | private | Legal but not an override, overridden method is not visible |
| protected | private | Illegal because, FootballPlayer.play can not be more restrictive. |
| protected | protected | Legal, access restrictions are at same level. |
| protected | public | Legal, FootballPlayer.play is less restrictive than Player.play. |
| public | private | Illegal. |
| public | protected | Illegal. |
| public | public | Legal. |
Rules of Overriding
- Argument list must match.
- Return type must match.
- Subclass’s method can not be more restrictive than super-class’s overridden method. See table above.
- Overriding method can throw any Runtime exception.
public class FootballPlayer extends Player{ private void play() throws RuntimeException{ //Legal System.out.println("I am a football player"); } private void play() throws SQLException{ //Illegal. In this situation Player's play method should throw broader exception //like java.lang.Exception System.out.println("I am a football player"); }
-
Player.play() FootballPlayer.play() Result throws SQLException throws Exception illegal, overriding method cannot throw a broader exception. throws SQLException throws SQLException Legal. throws Exception throws SQLException Legal. no exception throws SQLException Illegal. no exception throws NumberFormatException Legal because NumberFormatException is a RuntimeException. no exception throws RuntimeException Legal. - You can not override final methods.
- You can not override static methods.
How can you call a overridden method in a super-class.
public class Player { public void play() { System.out.println("I am a player"); } } public class FootballPlayer extends Player{ private void play() { super.play(); System.out.println("I am a football player"); } }
Output:
I am a player.
I am a football player.
Overloaded Methods
Overloading a method means, you can user same method name in a class more than once. But method parameters and optionally return types must be different of overloaded methods. A sub class can overload a method of superclass.
public class Player { String playerType = ""; public void setPlayerType(String playerType){ this.playerType = playerType; } } public class FootballPlayer extends Player{ String playerType = ""; public void setPlayerType(){ this.playerType = "football player"; } }
Here setPlayerType(String playerType) method is overloaded in FootballPlayer class.
public class Player { public void play(){ System.out.println("I am a player"); } } public class FootballPlayer extends Player { public void play(){ System.out.println("I am football player"); } public static void overLoaded(Player pl){ System.out.println("Player method"); } public static void overLoaded(FootballPlayer footballPl){ System.out.println("Football player method"); } public static void main(String args[]){ Player player = new Player(); Player footballPlayer = new FootballPlayer(); FootballPlayer.overLoaded(player); FootballPlayer.overLoaded(footballPlayer); } }
We have created two objects FootballPlayer and Player but using same type name Player. What does previous code print.
Output is :
Player method
Player method
Underlying object of footballPlayer variable is FootballPlayer at runtime but its type is Player. Overloaded method is called according to type, not underlying object. Because decision of which overloaded method will be called is made at compile time not at Runtime.
So it is important:
Decisions about overridden methods are done at runtime.
Decisions about overloaded methods are done at compile time.
Polymorphism cannot be applied overloaded methods because polymorphism is a runtime issue.
Can change
| Overloaded Methods | Overridden Methods | |
| Arguments | Need to change | Does not need |
| Return Type | Can change | Cannot change |
| Exceptions | Must be reduced or eliminated. | |
| Access | Can change | Cannot be more restrictive |
| Invocation | Based on variable type, decided in compile time | Decided according to underlying object type, decided in runtime |
Reference Variable Casting
Think about below scenario
class Car { } class Ferrari extends Car { public void enableRaceMode(){ System.out.println("Race mode enabled"); } } class Test { public static void main(String[] args){ Car c = new Ferrari(); if(c instanceof Ferrari){ c.enableRaceMode(); //compilation fails. } } }
Actually variable “c” refers to a Ferrari object, its type is Car and Car does not have a “enableRaceMode” method so how ca we make it compile.
class Test { public static void main(String[] args){ Car c = new Ferrari(); if(c instanceof Ferrari){ Ferrari f = (Ferrari)c; f.enableRaceMode(); //compilation fails. } } }
Here we made a down casting, Car object casted to Ferrari. What happens “Car c” refer to a Ford object and if we try to down cast “Car c” to Ford.
class Ford extends Car{} Car c = new Ford(); Ferrari f = (Ferrari)c;
Code compiles fine but throws ClassCastException at runtime thats why it is good to make an instanceof check before make a down casting.
Car c = new Ford(); if( c instanceof Ferrari){ Ferrari f = (Ferrari)c; // never executed }
As you know, Java does not support multiple inheritance, so you don’t need to declare superclass’ name at up casting. But superclass’ can have multiple subclasses so we need to write down casting to what ?
Ferrari f = new Ferrari(); Car c = f; // no need to Car c = (Car)f; c = new Ferrari(); Ferrari f = (Ferrari)c; //Down casting to Ferrari
Interfaces
Most important point about interfaces is you should implement all methods in your class , what you have defined in implemented interface. We have fly method in Flyable interface so all classes which are implement Flyable interface should have fly method. But why there is a strict rule like this.
Think about that:
Flyable flyable = new Pigeon(); flyable.fly();
For example Penguen class implements Flyable and does not have a fly method. (This is compiler error but let assume that this is valid in Java).
When we run
Flyable penguin = new Penguin(); penguen.fly();
In this situation jvm looks for “fly” method in Penguin class, but it does not exists, crash! But this was an u topic world, this kind of statement is already a compiler error.
interface Flyable{ public void fly(); } class Pigeon implements Flyable{ public void fly(){ System.out.println("I am pigeon, I can fly"); } }
Abstract classes and interfaces have similarities, abstract classes have abstract methods and these methods does not have body like interfaces. Lets look at combination of abstract classes and interfaces.
abstract class Bird implements Flyable{ abstract void eat(); }
You see, abstract class does contains fly method. Is this situation a compiler error ? No it is not, you can pass implementation first concrete subclass of Bird class.
class Cuckoo extends Bird { public void eat(){} public void fly(){} }
So a common interview question, why do we implements Runnable while we can already do same thing by extending Thread. Because Java does not support multiple inheritance, for example you have a frame which extends JFrame, and you want to add a background thread to your class. In this example you need to say extends JFrame,Thread but it is a illegal statement, you should use Runnable interface here like “extends JFrame implements Runnable”.
public interface Playable{} public interface Game{} public interface Soccer extends Playable, Game {} public class AmericanSoccer implements Soccer{}
Interfaces can extends more than one class unlike concrete or abstract classes.
There are two kinds of methods according to return type. If method does not return anything you should use “void myMethod(parameters)”, if method returns a value you should use “ReturnType myMethod(parameters)”.
public class Dog{ public void bark(){ System.out.println("woof, woof"); } } public class Cat{ public int getRemainingLives(){ return 9; } }
Return types of overloaded methods
The similarity between overloaded methods is same as similarity between Java and JavaScript and this means there is no similarity. Overloaded methods are totally different methods except their names. When you changed signature of a method you obtain an overloaded method. You can also freely change overloaded methods return types.
void play(){} String play(int playCount){}
Following code is illegal. If you
void play(){} String play(){}
Return Type of Overriding Methods
Return type and signature of a overriding method must be same, but overriding method can return a subclass of overridden method.
class Car{ public Car createNewCar(int parm){ return new Car(); } } class Ferrari extends Car(){ public Ferrari createNewCar(int parm){ return new Ferrari(); } }
Above feature enabled at Java 5. If you compile source with a 1.4 compile you will get a “attempting to use incompatible return type” error.
You can return null in any method except void return type.
public Ferrari createNewCar(int parm){ return null; //return null object reference. }
You can return Array.
public Ferrari createNewCars(int parm){ return new Ferrari[parm]; //return null object reference. then instantiate references. }
For primitive type, you can return any variable that can be convert declared type.
public int getInt(){ char c = 'c'; return c; }
You can return any value or variable that can be explicitly cast to declared type.
public int getInt(){ float x = 3.3f; return (int)x; }
You can return any object reference that can be implicitly cast to the declared return type.
public Car getCar(){ return new Ferrari(); }
You can return arrays as Object return type.
public Object getCar(){ return new String[]{"1","2","3"}; }
Return type can be an interface while returning value is an object which implements interface at return type.
public interface Flyable{} public Superman implements Flyable{} public Flyable getFlyable(){ return new Superman(); }
Constructors
Every class and abstract class should have a constructor. Constructors are called when we use “new” keyword. Every class should contains a constructor but probably you see definitions like,
class Car{}
Car class does not have a constructor definition but it does not mean that, Car class does not have a constructor. If no constructor is defined in class a default one is created. Default constructors are constructors with zero parameter.
class Car{ public Car(){} // constructor. }
Constructors are similar to methods but they do not have return type. No “void”,”int”,”String”,”Object” … And constructor name must be same as class name. If class name is Car constructors can be Car(), Car(int param1), Car(String param1,Object param2) …
We can overload constructors as we did in methods.
class Car{ public Car(){} // constructor no parameter public Car(int param1){} //constructor one parameter public Car(String param1,int param2){}//constructor with two parameter }
Usage:
Car c1 = new Car(); Car c2 = new Car(1); Car c3 = new Car("Race Car",1);
How constructors’ call flow occurs for following code.
class Car extends Object{} class Ferrari extends Car{}
When we run “new Ferrari()” code block,
- Ferrari’s default constructor calls Car’s default constructor
- Car’s default constructor calls Object’s default constructor.
- Object instance variables are given their explicit values.
- Object’s constructor is completed.
- Car instance variables are given their explicit values.
- Car’s constructor is completed
- Ferrari instances variables are given their explicit values.
- Ferrari’s constructor is completed.
Default Constructor
Follow the next three example to understand that when a default constructor will be created.
class Ferrari{ Ferrari(){} Ferrari(Color color){} }
Default constructor will not be created for above example because Ferrari class already has a constructor.
class Ferrari{ Ferrari(Color color){} }
Again a default constructor will not be created as in previous example. Because Ferrari class already has a constructor.
class Ferrari{} <pre>Yes a default constructor will be created this time because we have not defined any constructor for Ferrari class. There is only one rule you should remember about default constructor. If you have not defined any constructor in your class a default constructor will be created by compiler. <strong>Overloaded Constructors</strong> You can overload constructors as in methods. You can define more than one constructors with different argument type/count. <pre lang="java">class Ferrari{ Ferrari(Color color){} Ferrari(String model) Ferrari(){} }
Statics
If your method’s behavior does not depend on class’ instance variables, you should mark this method as static. All methods in java.lang.Math are static because return value of these methods do not depend on any instance variable. Usually utility classes have static methods.
You should use instance variables instead of static variables, but in some situations you can not. For example you want to know how many times an instance of a class is created. You cannot use an instance variable in this situation because an instance variable is always set to its default value at initialization. But value of a static variable does not change until you change it, value does not change even if a new instance created.
class Ferrari{ public static int INSTANCE_COUNT=0; public Ferrari(){ INSTANCE_COUNT++; } } new Ferrari(); new Ferrari(); new Ferrari(); new Ferrari(); System.out.println(Ferrari.INSTANCE_COUNT);
Result is 4 for above example.












