- Data Hiding
- Abstraction
- Encapsulation
- Has-A relationship
- Is-A relationship
- Method signature
- Overloading
- Overriding
- Method hiding
- Static control flow
- Instance control flow
- Constructors
- Coupling and Cohesion
1. Data Hiding
We are not allowed to provide access to our data directly to the outside person; we can achieve this by declaring data members as private. By this we can achieve security. It is highly recommended to declare data members as private.
2. Abstraction
Hiding implementation details is the concept of abstraction.
Adv:
a. Security: We are not highlighting our implementation
b. Enhancement: Without effecting outside person we are allowed to change our internal logic, hence enhancement is every easy.
c. It improves the maintainability (modularity)
3. Encapsulation
If any class follows data hiding and abstraction such type of class is said to be encapsulated class
i.e. Encapsulation = Data hiding + abstraction
eg:
class Student
{
private String name;
public String getName() // Accessor
{
return name;
}
public void setName(String name) // Mutator
{
this.name = name;
}
}
Here the outside person is not allowed to access our data directly. They can access by using getter and setter methods. Hence we are hiding the data behind the methods. This is the central concept of encapsulation.
Adv of Encapsulation:
a. Security
b. Enhancement
c. Improves maintainability
d. Modularity improves
Limitation of Encapsulation:
a. Encapsulation increases the code and slows down the execution.
Tightly encapsulated class
A class is said to be tightly encapsulated if and only all the data members declared as private.
Check which of the following classes are tightly encapsulated.
class Test{
private int x; // tightly encapsulated
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
//It is not tightly encapsulated
class Test{
int x = 10;
}
// A & C are tightly encapsulated
// B is not tightly encapsulated
class A{
private int x = 10;
}
class B extends A{
int y = 30;
}
class C extends B{
private int z = 40;
}
// A, B & C is not tightly encapsulated
// If the parent is not tightly encapsulated then no child class is tightly encapsulated
class A{
int x = 10;
}
class B extends A{
private int y = 30;
}
class C extends B{
private int z = 40;
}
4. IS – A Relationship: Inheritance
a. IS – A is also known as Inheritance.
b. By using extends keyword we can implement.
c. Reusability is the advantage.
Eg:
class Test{
public static void main (String args[]){
Parent p = new Parent();
p.m1(); //output - Parent m1
p.m2(); //output - Parent m2
p.m3(); //Compile Exception
Child c = new Child();
c.m1(); //output - Child m1
c.m2(); //output - Parent m2
c.m3(); //output - Child m3
Parent P = new Child();
p.m1(); //output - Child m1
p.m2(); //output - Parent m2
p.m3(); //Compile Exception
}
}
IMPORTANT
If the parent class reference can be used to hold child class object by using that reference we are allowed to call only parent class specific methods. If these methods are overridden in the child class then the child class methods will execute at runtime.
By using that reference, if we are trying to call child class specific method, we will get compile time error.
Limitation of inheritance:
For every child class object creation, all the parent class objects will be created automatically, sometimes it may creates side effects like performance problems. The industry standard accepted level of inheritance is 8.
5. HAS – A Relationship: (Aggregation or Composition)
a. HAS – A also known as Aggregation or composition
b. No specific name keyword (new operator we can use)
c. Reusability is the advantage
d. Limitation: The dependency between the components will increase so that maintainability and enhancement will become more complex.
// Class car has Engine reference
class Car{
Engine e = new Engine();
}
class Engine{
void m1(){}
void m2(){}
}
6. Method Signature
In java method signature consists of method name and arguments. Return type is not part of method signature.
Eg:
class Test{
public void m1(){} // m1() is the signature
public void m2(int i){} //m1(int i) is the signature
}
Compiler uses these signatures to map method calls with the method definitions.
Two methods having the same signature is not allowed in java violation leads to compile time error.
Eg:
class Test {
public void m1(){}
public int m1() { return 10;}
}
It will throw compileTimeException saying m1() is already defined in Test class
class Test{
public int m1(int i){
return 10;
}
Public void m1(int j) {}
}
It will throw compileTimeException saying m1() is already defined in Test class
7. Overloading
In the case of C language two methods with the same name are not allowed for example if we want to know absolute value, we have to use abs() method for integers, lafb() for long values, fabs() for float values. For every data type creating a new method name results more complexity. But in OOP languages two methods having the same is allowed based on the argument, the corresponding method will execute.
Two methods having the same name, but different arguments is possible in java. Such types of methods are considered as overloaded methods.
In the overloading, the signatures of the methods must be different. We never consider return types access modifiers, throws clause in the overloading.
Eg:
class Test{
public void m1(){
System.out.println(“No Arg”);
}
public void m1(int i){
System.out.println(“Int”);
}
public void m1(double d){
System.out.println(“double”);
}
public static void main (String args[]){
Test t = new Test();
t.m1();
t.m1(10);
t.m1(10l);
}
}
These methods are overloaded methods.
In the case of overloading the method resolution takes care by the compiler based on the reference type. Hence overloading is also considered as static polymorphism or Early Binding or Compile time polymorphism.
Case 1: Automatic promotion is overloading
public void m1(){
System.out.println(“No Arg”);
}
public void m1(int i){
System.out.println(“Int”);
}
public void m1(double d){
System.out.println(“double”);
}
public static void main (String args[]){
Test t = new Test();
t.m1(‘a’); //int
t.m1(10l); //double
t.m1(10f); //double
}
The char datatype automatically promoted to int data type by the compiler which is nothing but automatic promotion.
The following is the chart of automatic promotion:
byte -> short -> int -> long -> float ->double
char -> int -> long -> float ->double
Case 2:
class Test {
public void m1(int i, float f){
System.out.println(“int, float”);
}
public void m1(float f , int i){
System.out.println(“float, int”);
}
public static void main(String args[]){
Test t = new Test();
t.m1(10, 10.5f); // int, float
t.m1(10.5f, 10); // float, int
t.m1(10, 10); // compileTimeException refer to m1 is ambiguous
// (Here both methods are matchod)
}
}
Case 3:
class Test{
public void m1(String s){
System.out.println(“String version”);
}
public void m1(Object o){
System.out.println(“Object Version”);
}
public static void main (String args[]){
Test t = new Test();
t.m1(“Yash”); //String version
t.m1(new Object()); //Object version
}
}
Relation is there Object(Super), String(Child)
Case 4:
class Test{
public void m1(String s){
System.out.println(“String version”);
}
Public void m1(StringBuffer s){
System.out.println(“String Buffer Version”);
}
Public static void main (String args[]){
Test t = new Test();
t.m1(null); //CompileTimeException – ambiguous
// reference to m1 is ambiguous, both methods got matched
}
}
Here there is no relation between String and StringBuffer
Case 5:
class Test{
public void m1(int i){
System.out.println(“int method”);
}
public void m1(int... i){
System.out.println(“var-arg method”);
}
public static void main(String args[]){
Test t = new Test();
t.m1(); // output var-args method
t.m1(10,20); //output var-args method
t.m1(10); // output int method
}
}
Var-arg methods will always get least priority i.e. if there is no other method matched then only var-arg method will execute.
Case 6:
class Animal {}
class Monkey extends Animal{}
class Test{
public void m1(Animal a){
System.out.println(“Animal Version”);
}
public void m1(Monkey m){
System.out.println(“Monkey Version”);
}
public static void main (String args[]){
Test t = new Test();
Animal a = new Animal();
t.m1(a); // Animal Version
Monkey m = new Monkey();
t.m(m); // Monkey Version
Animal a1 = new Monkey();
t.m1(a1); //Animal version
}
}
In the case of method overloading method resolution is always takes care by compiler based on the reference type.
8. Overriding:
If the child class is not satisfied with parent class implementation, we are allowed to provide our own implementation in the child class. This concept is called overriding.
Eg:
class parent{
//Overridden method
void m1(){
System.out.println(“Parent m1”);
}
void m2(){
System.out.println(“Parent m2”);
}
}
class child extends parent{
//Overriding method
void m1(){
System.out.println(“Child m1”);
}
}
class Test{
public static void main(String args[]){
Parent p = new Child();
p.m1(); //Child m1
}
}
In the case of method overriding the method resolution always takes care by JVM based on the run time object. Hence overriding is also known as RunTime Polymorphism or Dynamic Polymorphism or Late Binding (until run time, which method will execute we don’t know)
The overriding method resolution is also known as “Dynamic Method Dispatch”.
Rules of Overriding:
1. Method name and list of arguments must be same i.e. Signature of the method name must be same.
2. In the case of overriding the return types must be same until java 1.4 version, but from java 1.5 version co-varient return types are also allowed i.e. If the parent class method return type is p then the return type of child class method need not be p its child classed are also allowed.
Eg 1:
Parent: Object m1(){}
Child: String m1(){}
1.4 – CompileTimeException
1.5 – Valid because co-variant return type allowed
Eg 2:
Parent: String m1(){}
Child: Objectm1(){}
CompileTimeException
Eg 3:
Parent: long m2(){}
Child: int m2(){}
CompileTimeException because return types not allowed for primitive types
Eg 4:
Parent: Long m1(){}
Child: Integer m1(){}
CompileTimeException
Private methods not visible in the child classes. Hence overriding concept is not applicable for private methods
We are not allowed to provide access to our data directly to the outside person; we can achieve this by declaring data members as private. By this we can achieve security. It is highly recommended to declare data members as private.
2. Abstraction
Hiding implementation details is the concept of abstraction.
Adv:
a. Security: We are not highlighting our implementation
b. Enhancement: Without effecting outside person we are allowed to change our internal logic, hence enhancement is every easy.
c. It improves the maintainability (modularity)
3. Encapsulation
If any class follows data hiding and abstraction such type of class is said to be encapsulated class
i.e. Encapsulation = Data hiding + abstraction
eg:
class Student
{
private String name;
public String getName() // Accessor
{
return name;
}
public void setName(String name) // Mutator
{
this.name = name;
}
}
Here the outside person is not allowed to access our data directly. They can access by using getter and setter methods. Hence we are hiding the data behind the methods. This is the central concept of encapsulation.
Adv of Encapsulation:
a. Security
b. Enhancement
c. Improves maintainability
d. Modularity improves
Limitation of Encapsulation:
a. Encapsulation increases the code and slows down the execution.
Tightly encapsulated class
A class is said to be tightly encapsulated if and only all the data members declared as private.
Check which of the following classes are tightly encapsulated.
class Test{
private int x; // tightly encapsulated
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
//It is not tightly encapsulated
class Test{
int x = 10;
}
// A & C are tightly encapsulated
// B is not tightly encapsulated
class A{
private int x = 10;
}
class B extends A{
int y = 30;
}
class C extends B{
private int z = 40;
}
// A, B & C is not tightly encapsulated
// If the parent is not tightly encapsulated then no child class is tightly encapsulated
class A{
int x = 10;
}
class B extends A{
private int y = 30;
}
class C extends B{
private int z = 40;
}
4. IS – A Relationship: Inheritance
a. IS – A is also known as Inheritance.
b. By using extends keyword we can implement.
c. Reusability is the advantage.
Eg:
class Test{
public static void main (String args[]){
Parent p = new Parent();
p.m1(); //output - Parent m1
p.m2(); //output - Parent m2
p.m3(); //Compile Exception
Child c = new Child();
c.m1(); //output - Child m1
c.m2(); //output - Parent m2
c.m3(); //output - Child m3
Parent P = new Child();
p.m1(); //output - Child m1
p.m2(); //output - Parent m2
p.m3(); //Compile Exception
}
}
IMPORTANT
If the parent class reference can be used to hold child class object by using that reference we are allowed to call only parent class specific methods. If these methods are overridden in the child class then the child class methods will execute at runtime.
By using that reference, if we are trying to call child class specific method, we will get compile time error.
Limitation of inheritance:
For every child class object creation, all the parent class objects will be created automatically, sometimes it may creates side effects like performance problems. The industry standard accepted level of inheritance is 8.
5. HAS – A Relationship: (Aggregation or Composition)
a. HAS – A also known as Aggregation or composition
b. No specific name keyword (new operator we can use)
c. Reusability is the advantage
d. Limitation: The dependency between the components will increase so that maintainability and enhancement will become more complex.
// Class car has Engine reference
class Car{
Engine e = new Engine();
}
class Engine{
void m1(){}
void m2(){}
}
6. Method Signature
In java method signature consists of method name and arguments. Return type is not part of method signature.
Eg:
class Test{
public void m1(){} // m1() is the signature
public void m2(int i){} //m1(int i) is the signature
}
Compiler uses these signatures to map method calls with the method definitions.
Two methods having the same signature is not allowed in java violation leads to compile time error.
Eg:
class Test {
public void m1(){}
public int m1() { return 10;}
}
It will throw compileTimeException saying m1() is already defined in Test class
class Test{
public int m1(int i){
return 10;
}
Public void m1(int j) {}
}
It will throw compileTimeException saying m1() is already defined in Test class
7. Overloading
In the case of C language two methods with the same name are not allowed for example if we want to know absolute value, we have to use abs() method for integers, lafb() for long values, fabs() for float values. For every data type creating a new method name results more complexity. But in OOP languages two methods having the same is allowed based on the argument, the corresponding method will execute.
Two methods having the same name, but different arguments is possible in java. Such types of methods are considered as overloaded methods.
In the overloading, the signatures of the methods must be different. We never consider return types access modifiers, throws clause in the overloading.
Eg:
class Test{
public void m1(){
System.out.println(“No Arg”);
}
public void m1(int i){
System.out.println(“Int”);
}
public void m1(double d){
System.out.println(“double”);
}
public static void main (String args[]){
Test t = new Test();
t.m1();
t.m1(10);
t.m1(10l);
}
}
These methods are overloaded methods.
In the case of overloading the method resolution takes care by the compiler based on the reference type. Hence overloading is also considered as static polymorphism or Early Binding or Compile time polymorphism.
Case 1: Automatic promotion is overloading
public void m1(){
System.out.println(“No Arg”);
}
public void m1(int i){
System.out.println(“Int”);
}
public void m1(double d){
System.out.println(“double”);
}
public static void main (String args[]){
Test t = new Test();
t.m1(‘a’); //int
t.m1(10l); //double
t.m1(10f); //double
}
The char datatype automatically promoted to int data type by the compiler which is nothing but automatic promotion.
The following is the chart of automatic promotion:
byte -> short -> int -> long -> float ->double
char -> int -> long -> float ->double
Case 2:
class Test {
public void m1(int i, float f){
System.out.println(“int, float”);
}
public void m1(float f , int i){
System.out.println(“float, int”);
}
public static void main(String args[]){
Test t = new Test();
t.m1(10, 10.5f); // int, float
t.m1(10.5f, 10); // float, int
t.m1(10, 10); // compileTimeException refer to m1 is ambiguous
// (Here both methods are matchod)
}
}
Case 3:
class Test{
public void m1(String s){
System.out.println(“String version”);
}
public void m1(Object o){
System.out.println(“Object Version”);
}
public static void main (String args[]){
Test t = new Test();
t.m1(“Yash”); //String version
t.m1(new Object()); //Object version
}
}
Relation is there Object(Super), String(Child)
Case 4:
class Test{
public void m1(String s){
System.out.println(“String version”);
}
Public void m1(StringBuffer s){
System.out.println(“String Buffer Version”);
}
Public static void main (String args[]){
Test t = new Test();
t.m1(null); //CompileTimeException – ambiguous
// reference to m1 is ambiguous, both methods got matched
}
}
Here there is no relation between String and StringBuffer
Case 5:
class Test{
public void m1(int i){
System.out.println(“int method”);
}
public void m1(int... i){
System.out.println(“var-arg method”);
}
public static void main(String args[]){
Test t = new Test();
t.m1(); // output var-args method
t.m1(10,20); //output var-args method
t.m1(10); // output int method
}
}
Var-arg methods will always get least priority i.e. if there is no other method matched then only var-arg method will execute.
Case 6:
class Animal {}
class Monkey extends Animal{}
class Test{
public void m1(Animal a){
System.out.println(“Animal Version”);
}
public void m1(Monkey m){
System.out.println(“Monkey Version”);
}
public static void main (String args[]){
Test t = new Test();
Animal a = new Animal();
t.m1(a); // Animal Version
Monkey m = new Monkey();
t.m(m); // Monkey Version
Animal a1 = new Monkey();
t.m1(a1); //Animal version
}
}
In the case of method overloading method resolution is always takes care by compiler based on the reference type.
8. Overriding:
If the child class is not satisfied with parent class implementation, we are allowed to provide our own implementation in the child class. This concept is called overriding.
Eg:
class parent{
//Overridden method
void m1(){
System.out.println(“Parent m1”);
}
void m2(){
System.out.println(“Parent m2”);
}
}
class child extends parent{
//Overriding method
void m1(){
System.out.println(“Child m1”);
}
}
class Test{
public static void main(String args[]){
Parent p = new Child();
p.m1(); //Child m1
}
}
In the case of method overriding the method resolution always takes care by JVM based on the run time object. Hence overriding is also known as RunTime Polymorphism or Dynamic Polymorphism or Late Binding (until run time, which method will execute we don’t know)
The overriding method resolution is also known as “Dynamic Method Dispatch”.
Rules of Overriding:
1. Method name and list of arguments must be same i.e. Signature of the method name must be same.
2. In the case of overriding the return types must be same until java 1.4 version, but from java 1.5 version co-varient return types are also allowed i.e. If the parent class method return type is p then the return type of child class method need not be p its child classed are also allowed.
Eg 1:
Parent: Object m1(){}
Child: String m1(){}
1.4 – CompileTimeException
1.5 – Valid because co-variant return type allowed
Eg 2:
Parent: String m1(){}
Child: Objectm1(){}
CompileTimeException
Eg 3:
Parent: long m2(){}
Child: int m2(){}
CompileTimeException because return types not allowed for primitive types
Eg 4:
Parent: Long m1(){}
Child: Integer m1(){}
CompileTimeException
Private methods not visible in the child classes. Hence overriding concept is not applicable for private methods
No comments:
Post a Comment