Tuesday, May 25, 2021

OOPS in java

 Data Hiding 

The internal data is protected from getting shared elsewhere unless the external side is verified.
eg: even if someone is a valid customer of the bank, then that person can access/obtain only his./her bank info. The main advantage is security.

in programming, by declaring data variables as private we can achieve data hiding. 

eg:
      public class Account
        {
            private double balance;

            public double getBalance()
                {
                    //verify the user and if valid execute next line
                    return balance;
                }
        }
[NOTE: it is highly recommended to declare data member as private]

Abstraction

Hiding internal implementation and highlighting only the set of services.
eg: there is n number of communications/operations happening b/w ATM machine and server, none are shown to the user only external few communication shown. 

Advantages:
1) Security: as we are not highlighting internal implementation.
2) Easy Enhancement: We can perform any changes in the internal system without affecting any external aspect.
3) it improves the maintainability of the system
4) it improves the ease of using the system.

by using interfaces and abstract classes we can implement abstraction .

Encapsulation

The process of binding data and corresponding methods into a single unit is encapsulation.
encapsulation= data hiding + abstraction 
the main advantage is we can achieve security
the disadvantage is it increases the length of the code and slows down execution

Tightly encapsulated class: iff all the variables are declared as private
eg:
      public class Account
        {
            private double balance; // only  variable is private 
            public double getBalance()
                {
                    //verify the user and if valid execute next line
                    return balance;
                }
        }
which of the following classes are tightly encapsulated
eg:  the ones marked in red are tightly encapsulated class 
     1)  class A
          {
             private int x=10;
          }
            class B extends  A
         {
            int y=10;
          }  
             class C extends  A
         {
            private int z=10;
          }        
 
2)  if the parent class is not tightly encapsulated the entire group is not tightly encapsulated
         class A
          {
             int x=10;
          }
            class B extends  A
         {
            int y=10;
          }  
             class C extends  A
         {
            private int z=10;
          } 

Inheritance - IS-A relationship 

By using extends keyword we can implement the IS-A relationship.

eg: 
public class Parent {
void m1()
{
System.out.println("parent method");
}
}
class Child extends Parent{
void m2()
{
System.out.println("child method");
}
}
case 1: Parent p = new Parent();
                p.m1();
                p.m2(); ------------------ error as the m2 method does not belong to class Parent
case 2 : Child c = new Child();
                c.m1();
                c.m2();
case 3 :  Parent p = new Child();
                p.m1();
                p.m2(); ------------------ error cannot find symbol m2
case 4:  Child c=new Parent(); ---------found Parent required Child 

Conclusion : 
1) whatever methods parent has is by default available to the child and not vice-versa, therefore the child has access to both parent and child methods
2) Parent reference can be used to hold child object but by using the reference we cannot call child-specific methods i.e we can call methods present in the parent class (case 3).
3) Parent reference can be used to hold a child object but child reference cannot be used to hold a parent object (case 4).

Without inheritance

class HLoan                                Class VLoan                                 Class  PLoan
{                                                 {                                                     {
//300 methods                             //300 methods                                    //300 methods
}                                                  }                                                     }


With inheritance

                                                        class Loan
                                                        {
                                                           //250 common methods
                                                         }

class HLoan  extends Loan              Class VLoan  extends Loan              Class  PLoan extends Loan
{                                                         {                                                               {
//50 specific methods                          //50 specific methods                              //50 specific methods
}                                                          }                                                              }

multiple inheritance: java class won't support multiple inheritance 
eg: if there are two parent class p1,p2 with the same method name m1 then there will be an ambiguity problem.

Interfaces can extend any number of interfaces hence java supports multiple inheritance with respect to interfaces.  

cyclic inheritance: cyclic inheritance is not allowed in java
eg : 
class P extends C{
}
class C extends P{
}
Error:(6, 1) java: cyclic inheritance involving P

HAS-A relationship

  1. Is also known as composition/aggregation.
  2. There is no specific keyword to implement has-a relationship
  3. The main advantage of HAS-A is code reusability.
eg: class Car
        { 
            Engine e=new Engine();
         }

        Car HAS-A engine reference.

Difference b/w composition and aggregation.

Composition: without an existing container object if there is no chance of existing contained objects, container and contained objects are strongly associated and this strong association is nothing but composition.
eg: university consists of several departments, without existing university there is no chance of existing department hence university and department are strongly associated and this strong association is nothing but composition.
 eg:                                                              University
      In the above example, a university is a container object and the depts are contained objects.

Aggregation: without an existing container object if there is a chance of existing contained object, then container and contained objects are weekly associated and this week association is nothing with aggregation.
eg: dept consists of several professors, without existing department there may be a chance of existing professor objects, hence department and professor objects are weekly associated and this weak association is nothing but aggregation.

Note:1) in composition objects are strongly associated whereas in aggregation objects are weekly associated.
2) in composition container object holds contained objects directly whereas in aggregation container object just holds the reference of contained objects.

IS-A versus HAS-A


if we want total functionality of class automatically then we should go for IS-A relationaship.
eg : Person IS-A Student  : the total functionality of Person class is needed for Student class. (Student extends Person)

if we want part of the functionality the we should go for HAS-A relationaship
eg: Demo HAS-A Test : Test class has 100 method out of which only 2-3 is needed hence use reference.
class Test 
   {
        //100 methods
    }
class Demo // needs only 2-3 methods of class Test
    {
        Test t=new Test();
        t.m1();
    }

Method signature: in Java, method signature consists of method names followed by argument types
eg :     public static int m1(int i , float f)  -----------------> m1(int,float) 
(return type is not a part of a method signature in java)

the compiler will use method signature to resolve method calls.
eg: class Test
{
    public void m1(int i) {
    }
}
Test t=new Test();
t.m1(11);
t.
m2(5.6); --Error : java: cannot find symbol symbol: method m2(double)
2)within a class 2 method with the same signature is not allowed
class Test
{
    public void m1(int i) {
    }
    public void m1(int j){
    }
}
Error: java: method m1(int) is already defined in class Test.

Overloading

Two methods are said to be overloading iff both methods have same name but different arguments. In C method overloading concept is not available hence we cant declare multiple methods with the same name and different argument types. If there is a change in argument type we will need to go for a new method which increases complexity.
eg: absolute function in java ----- abs(int/float/long)   in C abs(int) , labs(long), fabs(float)  

this java concept reduces the complexity of programming.
in overloading method resolution is always taken care by the compiler based on reference type hence overloading is also known as compile-time polymorphism/static polymorphism/early binding.

Some cases with overloading.
Case 1: overloading int method with a char argument (automatic promotion in overloading) it will promote argument to next level and check if the matched method is available or not , if not available this process is continued till all possible promotions if still not matched we will get a compile-time error.
the flow is in order  byte,short/char-->int-->long-->float-->double
eg: 
class Test
{
    public void m1(int i) {
    }
    public void m1(float f){
    }
}
class Demo
{
    public static void main(String[] args) {
        Test t=new Test();
        t.m1(11);
        t.m1('a') ;  ----> char will be accepted as int
        t.m1(19L) --> will be accepted as Float.
    }
}

case 2: while resolving overloaded methods compiler will always give precedence to child object instead of parent.
eg:
class Test
{
    public void m1(String s) {
    }
    public void m1(Object o){
    }
}

Test t=new Test();
 t.m1("string");  ------> string version
 t.m1(new Object()); ------> object version
 t.m1(null); ------>string version.

case 3: if both the method arguments have the same precedence we will get a compile-time error.
eg:
class Test
{
    public void m1(String s) {
    }
    public void m1(StringBuffer sb){
    }
}

Test t=new Test();
 t.m1("string");  ------> string version
 t.m1(new StringBuffer("abc")); ------>StringBuffer  version
 t.m1(null); ------> compiler error: reference to m1() is ambigous.

Case 4: 
eg:
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");
    }
}
Test t = new Test();
 t.m1(10, 10f);  ---------------> int-float
 t.m1(10f, 10);  ---------------> float-int
 t.m1(10, 10);  --------------->  Error: java: reference to m1 is ambiguous
  both method m1(int,float) in Test and method m1(float,int) in Test match.

Case 5: in general vararg method will get the least priority, i.e if no other matched then vararg will get a chance (like default case inside switch)
eg:
class Test
{
    public void m1(int i) {
        System.out.println("int");;
    }
    public void m1(int... i){
        System.out.println("vararg int");
    }
}
Test t = new Test();
t.m1(); -------> vararg method
t.m1(20, 10); ------>vararg method
t.m1(10); -----> general method 

Case 6 : In the overloading method resolution always taken care by the compiler based on reference type, in overloading run time objects don't play a major role.
eg:
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");
    }
}
Test t=new Test();
 t.m1(new Animal()); ----> animal version method
 t.m1(new Monkey());  -----> monkey version method
 Animal a=new Monkey(); ------> animal version method based on type of reference
 t.m1(a);

Overriding

All the methods of parent class are available to child class by default through inheritance. If a child class is not satisfied with parent class implementation then the child is allowed to redefine the method based on the requirement.  the Parent class method which is overridden is called overridden method and the child class method which is overriding is called the overriding method.
 
Eg: class Parent
        {
            public void marry(){
            }
         }
        class Child extends Parent
         {
            public void marry() {
            }
          }

Parent p = new Parent();
p.marry();   ---------> parent method is called
Child c =new Child();
c.marry();  ----------> Child method is called.
Parent p1=new Child();
p1.marry();   -------> child method is called as marry() method is overridden in child class
In overriding method resolution always taken care by JVM based on `runtime object` and hence overriding is also called runtime polymorphism/ late binding / dynamic binding.

Rules for overriding:

  1.  In the overriding method names and argument types must be the same i.e method signatures must be the same. 
  2. In overriding return types must be the same but this rule is applicable only till 1.4 version but 1.5 version onwards we can have co-variant return type i.e overridden and overriding methods need not have same return type.
  3. child method return type should be the same or child of parent return type. in case of primitives, it should always be same. eg: if parent has Object then child can have String, StringBuffer etc...
  4. Parent class private methods are unavailable to the child hence overriding methods not possible, Even though we can define exactly the same private method in child class which is valid but not overriding.
  5. final methods cannot be overridden.
  6. Parent class abstract methods we should override in child class to provide the implementation.
  7. We can override non-abstract method as abstract. the main advantage of this approach is we can stop the availability of parent method implementation to next level classes.
  8. In overriding, the following modifiers wont keep any restriction  i.e (synchronized, native, strict fop)
  9. We cant reduce the scope of access modifiers, i.e if the parent method is public the child method should be public only else it can't override. (private<default<protected<public)
  10. If the child class throws any exception then the parent class method must throw the same checked exception or its parent otherwise we will get a compile-time error. ( there are no rules for unchecked exception)
Overriding with respect to static methods
1) we can't override a static method as non-static 
eg: 
class Parent{
    public static void m1(){}
}
class Child extends Parent{
    public void m1() {}
}
Error: java: m1() in Child cannot override m1() in Parent; overridden method is static

2) we cant override non-static method as static.
eg:
class Parent{
    public void m1() {}
}
class Child extends Parent{
    public static void m1() {}
}
Error:java: m1() in Child cannot override m1() in Parent; the overriding method is static

3) if both parent and child class methods are static then we won't get any compile-time error. it seems an overriding concept applicable for static methods. it is not overriding and method hiding.
eg:
class Parent{
    public static void m1() {}
}
class Child extends Parent{
    public static void m1() {}
}

Method hiding

All rules of method hiding are same as overriding except the following differences.
    1) Both parent and child methods should be static.
    2) method resolution always taken care by compiler based on reference type.
    3) also known as compile time polymorphism/static polymorphism/early binding.
eg:
class Parent{
    public static void m1() {}
}
class Child extends Parent{
    public static void m1() {}
}
        Parent p=new Parent();
         p.m1(); -----------------------> Parent method
        Child c=new Child();
        c.m1();  -----------------------> Child method
        Parent p1=new Child();
        p1.m1(); -----------------------> Parent method

in hiding both copies are available only one with reference is shown, in overriding only a new copy is available, not an old copy.

Overriding WRT Vararg methods

When two methods have the same name but different arguments then it is overloading not overriding.
We can override vararg method with another vararg method only, if we try to override without vararg then it is overloading.
eg:
class Parent{
    public static void m1(int... x) {}
}
class Child extends Parent{
    public static void m1(int x) {}
}
        Parent p=new Parent();
         p.m1(); -----------------------> Parent method
        Child c=new Child();
        c.m1();  -----------------------> Child method
        Parent p1=new Child();
        p1.m1(); -----------------------> Parent method

in the above program if we replace the child method with vararg method then it will become overriding, in this case the output is Parent, child, child.

Overriding WRTo variables 

Overriding concept applicable only for methods, not variables. Variable resolution is always taken care by the compiler based on reference type irrespective of whether the variable is static/non-static. 
eg:
class Parent{
    int x=888;       
}
class Child extends Parent{
     int x=999;
}
         Parent p=new Parent();
        System.out.println(p.x);  ------------> 888
        Child c=new Child();
        System.out.println(c.x);   ------------> 999
        Parent p1=new Child();
        System.out.println(p1.x);  ------------>888

the output remains the same irrespective of if the variable is static or normal.

Difference b/w overloading and overriding

1) Argument type
overloading: must be different (at least shuffle the order)
overriding: must be the same including order.
2) Method signatures
overloading: must be different
overriding: must be same
3) return types
overloading: no restriction
overriding: must be same till version 1.4 also from 1.5 version onwards co-variant return types allowed.
4) private,static,final methods
overloading: can be overloaded
overriding: cannot be overridden
5)Access modifiers 
overlading: No restrictions
overriding:  the scope of access modifier should not be reduced only increased or same
6) throws clause
overloading: No Restrictions
overriding: If child class throws any checked exception then compulsorily parent class method must throw the same checked exception or its parent. ( no restriction for unchecked exception)
7) Method resolution
overloading: always taken care by the compiler based on the reference type.
overriding: always taken care by the JVM  based on runtime object
8) also known as
overloading: compile time polymorphism/static polymorphism/early binding.
overriding: run time polymorphism/ dynamic polymorphism /late binding. 

[Note: in overloading, we have to check only method names ( must be same) and argument types must be different, we are not required to check remaining like return types/access modifiers etc. in overriding we have to check everything like method names argument types return types access modifiers, throws class, etc]

Consider the following method in parent class

public void m1(int x) throws IOException    
In the child class which are the following methods we can implement.
1)  public void m1(int i)     -------> overriding
2)  public static int m1(long l)    ---------> overloading
3)  public static void m1(int i)    --------> cant override as the static cant be either at parent/child level
4)  public void m1(int i) throws Exception   -----> parent method must have same or parent exception
5)  public static abstract void m1(int x)  ---> abstract and static keyword cant be together.

Polymorphism

one name but multiple forms is the concept of polymorphism.
eg1: method name is same but we can apply different  type of arguments (overloading)
abs(int) ,abs(long) , abs(float)
eg2: method signature is the same but different implementation in parent and child class. (overriding)
eg 3: usage of parent reference to hold child object is also polymorphism.
List l=  new ArrayList();    List L=new LinkedList();

Parent class reference can be used to hold child object but by using that reference we can call only the methods available in parent class but by using child reference we can call both parent and child class methods.

when to use Parent reference to hold child object.
) if we don't know exact runtime type of object then we should go for parent reference. 
eg: the first element present in ArrayList can be any type (string/Strinfbuffer/Student/Customer  object) hence return type of get method is object which can hold any object
List l=new List();      Object o = l.get(0);

Child c=new Child(); versus Parent p=new Child();

1) Child c=new Child();    i.e eg: ArrayList l=new ArrayList();
  • We can use this approach if we know exact runtime type of object 
  • by using child reference we can call both parent class and child class methods (advantage of this approach)
  • we can use child reference to hold only particular child class objects.
2) Parent p = new Child();     i.e List l=new ArrayList();
  • We can use this approach if we don't know the exact runtime type of object.
  • by using parent reference we can call only parent class methods
  • we can use parent reference to hold any child class object. this is the advantage of this approach.


Fun fact: A boy starts Love with the word Friendship, but the Girl ends Love with the same word Friendship
This beautiful concept of OOPS is nothing but polymorphism...

COUPLING

 the degree of dependency between components is called coupling. is dependency is more than it is considered as tightly coupling and if dependency is less then it is considered as loosely coupling.

Tightly coupled

class A                      class B                 class C                            class D
{                              {                            {                                    {
static int i=B.j;         static int j =C.k;    static int k=D.m1();       public static int m1() { 
                                                                                                      return 10;}
}                               }                            }                                    }
Tightly coupled classes
the above components are said to be tightly coupled with each other because dependency between components is more. Tightly coupling is not a good programming practice because it has several serious disadvantages
1) without affecting the remaining components we cant modify any component and hence enhancement will become difficult.
2) it suppresses reusability.
3) it reduces the maintainability of the application.
hence we have to maintain dependency between the components as less as possible therefore Loosely coupling is the best practice.

Cohesion

for every component a clear well-defined functionality is defined then that component is said to follow high cohesion.
high cohesion is always a good programming practice because it has several advantages 
1) without affecting remaining components we can modify any component hence enhancement will become easy
2)  it promotes the reusability of the code. ( wherever validation is required we can reuse the same servlet without writing)
3) it improves the maintainability of the application.

Note:" loosely coupling and high cohesion are good programming practices"

Object type casting // recheck

we can use parent reference to hold child object 
Object o=new String("str");

we can use interface reference to hold implemented class objects.
eg: runnable r=new Thread();

A  b=(C) d;

A/C-class/interface name , b/d=name of reference variable, 

compile-time check 1: the type of d and c must have some relation either child to parent or parent to child or the same type otherwise we will get a compile-time error (inconvertible type requires C found D)
eg1: the below example is valid 
Object o=new String("romy");
StringBuffer sb=(StringBuffer) o;

eg2: the below example is not valid
String st=new String("a");
StringBuffer sb1=(StringBuffer) st;
Error: java: incompatible types: java.lang.String cannot be converted to java.lang.StringBuffer

compile-time check 2: C must be either same or derived type of A otherwise we will get a compile-time error saying found C requires A
eg1: the below example is valid
Object o=new String("romy");
StringBuffer sb=(StringBuffer) o;

eg2: 
Object o=new String("romy");
StringBuffer sb=(String) o;
Error:java: incompatible types: java.lang.String cannot be converted to java.lang.StringBuffer

run time check: run time object type of d should be either same or derived type of C else we will get run-time error i.e class cast exception.
eg 1:
Object o=new String("romy");
StringBuffer sb=(StringBuffer) o;
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.StringBuffer 

eg2: 
Object o=new String("romy");
Object o1=(String) o;
works fine

revise All cases/rules for object typecasting example.

Typecasting

Strictly speaking through typecasting we are not creating any new object, for the existing object we are providing another type of reference variable. i.e we are performing typecasting not object casting.
eg 1: String s=new String("romy");   Object o=(Object) s;  
      can be written as Object o=new String("durga");  as shown below

 eg2:  Integer i = new Integer(10);
          Number n= (Number) i;
          Object o=(Object) n
in the above example line 1 and line 2 can be combined and written as 
          Number n =new Integer(10);
all the 3 llines can be combined and written as 
         Object o=new Integer(20);
therefore i==n will be true similarly i==o will be true too.

eg 3: consider Parent methods P with method m1() and Child class C with method m2()
C c=new C();
c.m1(); --- valid
c.m2(); ---- valid 
((P)c).m1(); ---- valid
((P)c).m2(); ---- invalid
reason: parent reference can be used to hold child object but by using the reference we cant call child-specific method 

eg 4:  if there are 3 class A,B,C where class C is the child of B and B is the child of A (C--->B--->A) and all the three class has a method named m1(), hence it will be method overriding.
          class A{
            void m1() {}  }
          class B extends A{
            void m1() {} }
          class C extends B{
            void m1() {} }

C c=new C();
c.m1(); -----> C.m1()
((B)c).m1(); -----> C.m1()
((A)((B)c).m1(); -----> C.m1()
it is overriding and method resolution is always based on run time object.

eg 5: the scenario is the same as the previous example but all the methods are static.
that will be the concept of method hiding and method resolution is always based on the reference type.
C c=new C();
c.m1(); -----> C.m1()
((B)c).m1(); -----> B.m1()
((A)((B)c).m1(); -----> A.m1()

eg 6:  class A{
            int x=999; }
          class B extends A{
            int x=888; }
          class C extends B{
            int x=777; }

C c=new C();
c.x; -----> 777
((B)c).x; -----> 888
(A)((B)c).x; -----> 999

variable resolution is always based on reference type and not run-time object.

Static control flow

Whenever we are executing a java class the following sequence of steps will be executed as a part of static control flow.
1) Identification of static members from top to bottom. [ 1to 6]
2) Execution of static variable assignments and static blocks from top to bottom. [7 to 12]
3) Execution of the main method [13 to 15]
eg:
(1)class Demo
{
 static int i=10;(7)   ---> initially i=0 due to RIWO
(2) static {
     m1(); (8)
     System.out.println("first static block"); (10)
 }
(3)public static void main(String[] args) {
        m1(); (13)
        System.out.println("main method"); (15)
    }
 (4) public static void m1(){
        System.out.println(j); (9) , (14)
    }
(5) static{
     System.out.println("second static block"); (11)
 }
 (6) static int j=20; (12)   ---> initially i=0 due to RIWO
}
output :
0
first static block
second static block
20
main method

Read indirectly write-only (RIWO):  inside the static block, if we are trying to read a variable that read operation is called "direct-read". If we are calling a method and within that method if we are trying to read a variable that read operation is called "indirect-read".
eg:
class Demo
{
 static int i=10;
 static {
     m1();
     System.out.println(i);  ------> direct read
 }
public static void m1(){
        System.out.println(i);   ----------> indirect read
}  }
if a variable is just identified with JVM and the original value not yet assigned then the variable is said to be in read indirectly and write only state (RIWO).
if a variable is in RIWO state then we cant perform direct read but we can perform indirect read. failing to which we will get "illegal forward reference compile-time error".
eg 1 :
class Demo
{
 static int i=10;
 static {
     System.out.println(i);
 }
}
O/P: 10

eg 2:
class Demo
{
 static {
     System.out.println(i);
 }
static int i=10;
}
Error: java: illegal forward reference

eg 3:
class Demo
{
 static {
     m1();
 }
public static void m1()
 {
     System.out.println(i);
 }
static int i=10;
}
O/P : 0

Static block

Static blocks will be executed at the time of class loading hence at the time of class loading if we want to perform any operation we have to declare that in the static block.
at the time of java class loading, the corresponding native libraries should be loaded hence we have to declare this activity inside the static block.
eg: after loading every DB driver class we have to register driver class with driver name but in DB driver there is a static block to perform this operation.
class DBdriver
{
static {
Register this driver with the manager
}
}
within a class, we can declare any number of static blocks all these static blocks will be executed top to bottom.

Without writing the main method is it possible to print some statements to the console?
yes, by using static block. (till 1.6V)
class Test
{
static{
sout "output";
System.exit(0);
}
}

Without writing the main method and the static block is it possible to print some statements to the console?
- yes, there are multiple ways to do so.
class Test
{
static int var=m1();
public statiuc void m1(){
sout("print");
System.exit();
}
}

class Test
{
static Test t=new Test();
{
sout("print");
System.exit(0);
}
}

class Test
{
static Test t=new Test();
Test(){
sout("print");
System.exit(0);
}
}

from the 1.7 version onwards to start execution of the java program main method is mandatory. hence it is not possible to print anything without a main method.

Static control flow in parent to child relationship

whenever we are executing child class then the following sequence of events will be executed automatically as a part of static control flow
1) identification of static members from parent to child.
2) execution of static variable assignments and static blocks from parent to child.
3) execution of only child class main method.

class Demo
{
(1)static int i=10; (12)  //initially i=j=x=y=0 [RIWO]
 (2)static {
     m1();(13)
     System.out.println("child static block");(15)
 }
   (3)public static void main(String[] args) {
        m1();
        System.out.println("main method");
    }
   (4)public static void m1(){
        System.out.println(j);(14)
    }
    (5)static int j=20;(16)
}
class Derived extends Demo
{
    (6)static int x=12;(17)
    (7)static {
        m2();(18)
        System.out.println("child static block");(20)
    }
    (8)public static void main(String[] args) {
        m2();(23)
        System.out.println("child main");(25)
    }
   (9)public static void m2() {
        System.out.println(y);(19),(24)
    }
    (10)static {
        System.out.println("child second static block");(21)
    }
    (11)static int y=23;(22)
}
Output:
0
parent static block
0
child static block
child second static block
23
child main

[Note: whenever we are loading child class automatically Parent class will e loaded but it is not vice-versa(parent class members by default available to child and child class member not available to parent)]

Instance control flow

Whenever we are executing java class first the static control flow will be executed, in the static control flow if we are creating object the following sequence of events are executed as a part of instance control flow.
1) identififcation of instance members from top to bottom (3) to (8)
2) execution of instsance variable assignments and instance blocks from top to bottom. (9) to (14)
3) execution of constructor. (15)
eg:
public class Test {
 (3)int i=10; (9)
(4){
        m1();(10)
        System.out.println("first instance block"); (12)
    }
(5) Test(){
        System.out.println("constructor"); (15)
    }
   (1) public static void main(String[] args) {
    (2) Test t=new Test();  -----------> [Line 1]
     (16) System.out.println("main method");
    }
(6)public void m1(){
        System.out.println(j); (11)
    }
(7){
        System.out.println("second block"); (13)
    }
(8) int j=30; (14)
}
Output:
0
first instance block
second block
constructor
main method

if we comment [line 1] then the comment is "main method"

[Note: Static control flow is one-time activity that will be performed but instance control flow is not one-time activity and it will be performed for every object creation. Object creation is the most costly operation if it is not required then it is not recommended to create an object.]

Instance control flow in parent to child relationship

whenever we are creating child class objects the following sequnce of events will be performed automatically as the part of instance control flow
1) identification of instance members from parent to child (4) to (14)
2) execution of instance variable assignments and instance blocks only in the parent class. (15) to (19)
3) execution of parent constructor. (20)
4) execution of instance variable assignments and instance blocks in child class. (21) to (26)
5) execution of child constructor. (27)
eg:
class Parent{
(4)int i=888;  (15)
(5){
        m1(); (16)
        System.out.println("Parent instance block"); (18)
    }
 (6) Parent(){
        System.out.println("constructor"); (20)
    }
   (1) public static void main(String[] args) {
        Parent p=new Parent();
        System.out.println("Parent main");
    }
  (7)public void m1() {
        System.out.println(j); (17)
    }
   (8) int j=999; (19)
}
class Child extends Parent{
  (9)int x=777; (21)
  (10){
        m2(); (22)
        System.out.println("child first instance block"); (24)
     }
  (11)Child{
        System.out.println("child constructor"); (27)
    }
   (2) public static void main(String[] args) {
    (3) Child c=new Child();
        System.out.println("child main");
    }
 (12) public void m2(){
        System.out.println(y); (23)
    }
 (13) {
        System.out.println("child second instance block"); (25)
    }
 (14) int y=666; (26)
}
Output:
0
Parent instance block
constructor
0
child first instance block
child second instance block
child constructor
child main

Eg 2: please print the output
public class Test {
    {
        System.out.println("first instance block");
    }
    static {
        System.out.println("first static block");
    }
    Test(){
        System.out.println("constructor");
    }
    public static void main(String[] args) {
        Test t=new Test();
        System.out.println("main method");
        Test t1=new Test();
    }
    static {
        System.out.println("second static block");
    }
    {
        System.out.println("second instance block");
    }
}
Output:
first static block
second static block
first instance block
second instance block
constructor
main method
first instance block
second instance block
constructor

eg 3: please guess the output
public class Initialization {
    private static String m1(String msg) {
        System.out.println(msg);
        return msg;
    }
    public Initialization(){
        m=m1("1");
    }
    {
        m=m1("2");
    }
    String m=m1("3");

    public static void main(String[] args) {
        Object o=new Initialization();
    }
}
Output:
2
3
1

Eg 4:
public class Initialization {
    private static String m1(String msg) {
        System.out.println(msg);
        return msg;
    }
    static String m=m1("1");
    {
        m=m1("2");
    }
    static {
        m=m1("3");
    }
    public static void main(String[] args) {
        Object o=new Initialization();
    }
}
Output:
1
3
2

Eg 5:
public class Test1 {
    int x=10;
    public static void main(String[] args) {
        System.out.println(x);
    }
CE: Error: java: non-static variable x cannot be referenced from a static context.

Note: from the static area, we cant access instance members directly because while executing the static area JVM may not identify instance members

In how many ways we can create an object in Java

1) By using new keyword
Test t=new Test();

2) By using newInstance() method:
Test t=(Test) Class.forName("Test").newInstance();

3) By using factory method
Runtime r=Runtimr.getRuntime();
DateFormat df=DateFormat.getInstance();

4) By using clone() method:
Test t1=new Test();
Test t2=(Test) t2.clone();

5) By using Deserialization
FileInputStream fis=new FIS("abc.scr");
ObjectInputStream ois=new OIS(fis);
Dog d2=(Dog) ois.readObject();

Inner class in java

introduced in version 1.0
without existing one kind of object if there is no chance of existing of another type of object then we will be needing inner class concept.
eg: university consists of department , engine object needs car object to exist.
there are 4 types of inner class.
1) regular inner class                    2)method local inner class
3) anonymous inner class             4)static nested classes

 1) regular inner class

examples with several instances
class Outer {
class Inner{
}
}
in the above example two .class files are created Outer.class and Outer$Inner.class .

example 2:
class Outer {
class Inner{
public static void main(String[] args) {
System.out.println("inside inner class");
}
}
}
O/P : Error:(8, 28) java: Illegal static declaration in inner class Abstarct.Outer.Inner
  modifier 'static' is only allowed in constant variable declarations

example 3: in order to create a Inner class method
class Outer {
class Inner{
public void m1() {
System.out.println("method inside inner class");
}
}
public static void main(String[] args) {
Outer o=new Outer();
Outer.Inner i=o.new Inner();
i.m1();
}
}
O/P: method inside inner class

can also be written as
class Outer {
class Inner{
public void m1() {
System.out.println("method inside inner class");
}
}
public static void main(String[] args) {
Outer.Inner i=new Outer().new Inner();
i.m1();
}
}

example 3: accessing inner class code from instance area of outer class : Inner i=new Inner() ; would be enough.
class Outer {
class Inner{
public void m1() {
System.out.println("method inside inner class");
}
}
void m2(){
Inner i=new Inner();
i.m1();
}
public static void main(String[] args) {
Outer o=new Outer();
o.m2();
}
}
O/P: method inside inner class

Example 4: accessing inner class code from outside of outer class
class Outer {
class Inner{
public void m1() {
System.out.println("method inside inner class");
}
}
}
class Test{
public static void main(String[] args) {
Outer.Inner i=new Outer().new Inner();
i.m1();
}
}
O/P: method inside inner class

Example 5: we can acces both static and non static members
class Outer {
int x=10;
static int y=11;
class Inner{
public void m1() {
System.out.println(x);
System.out.println(y);
}
}
}
class Test{
public static void main(String[] args) {
new
Outer().new Inner().m1();
}
}
O/P : 10
11

Example 6: this refers to inner class to refer current outer class object we have to use <outerclassname>.this
class Outer {
int x=10;
class Inner{
int x=100;
public void m1() {
int x=1000;
System.out.println(x);
System.out.println(this.x);
System.out.println(Outer.this.x);
}
}
}
class Test{
public static void main(String[] args) {
new Outer().new Inner().m1();
}
}
O/P:1000
100
10

Note : the only applicable modifier for outer class are public, default , final , abstract, strictfop.
whereas for inner class public, default , final ,abstaract, strictfop + private,protected,static.

nesting of inner classes

inside inner classes we can declare another class and so on which is known as inner class.
eg:
class Outer {
class A{
class B{
class C{
public void m1(){
System.out.println("inside innermost class");
}
}
}
}
}
class Test{
public static void main(String[] args) {
new Outer().new A().new B().new C().m1();
}
}
O/P: inside innermost class 

2)Method local innerclasses

We can declare a class inside a method, such type of innerclass are called method local innerclass.
the main purpose her eis to define method specific repeated functionality. it is rarely used due to less variable scope.
eg 1:
class Outer {
public void m1(){
class Inner{
public void m2(){
System.out.println("inner most method");
}
}
Inner i=new Inner();
i.m2();
}
}
class Test{
public static void main(String[] args) {
Outer o=new Outer();
o.m1();
}
}
O/P: inner most method

Note: we can declare method local inner class inside both normal and static methods.
if we declare method as static then we can't access non static variables from outer class.

example 2: from method local inner class , we cant access local variables of method in which we declare inner class , if the local variable declared as final then we can access.
class Outer {
public void m1(){
int x=10; // preffered to be final
class Inner{
public void m2(){
System.out.println(x);
}
}
Inner i=new Inner();
i.m2();
}
}
class Test{
public static void main(String[] args) {
Outer o=new Outer();
o.m1();
}
}
O/P : 10

inside inner class we cant declare any method as static.

3)Anonymous inner classes

declaring inner class without name is anonymous inner class.its main purpose is instant use.

based on declaration and behavior there are three types 
1) anonymous innerclass that extends a class.
2) that implements an interface
3) that is defined inside arguments.

anonymous innerclass that extends a class.

example1:
class Outer {
public void m1() {
System.out.println("method m1");
}
}
class Test{
public static void main(String[] args) {
Outer o=new Outer(){
public void m1(){
System.out.println("hahahaha");
}
};
o.m1();
}
}
O/P: hahahaha

3 class files are created Outer.class , Test.class , Test$1.class(for anonymous class)  .

 analysis
1) Outer o=new Outer();  -> a simple object;
2) Outer o=new Outer(){ 
                                        }; -> we are dceclaring a classs that extends Outer without name(anonymous)
3) Outer o=new Outer(){
   public void m1(){
                System.out.println("hahahaha");
            }
;  -> in the child class we are overriding m1() method.

defining a thread by extending thread class.

class Test {
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("inner thread");
}
}
};
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("main thread");
}
}
}
O/P:
main thread
inner thread
main thread
main thread
main thread
main thread
inner thread
inner thread
inner thread
inner thread

anonymous inner class that implements an interface.

Example 1: defining a thread by implementing runnable interface
class Test {
public static void main(String[] args) {
Runnable r=new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("child thread");
}
}
};
Thread t=new Thread(r);
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("main thread");
}
}
}

anonymous inner class that is defined in arguments.

class Test {
public static void main(String[] args) {
Thread t=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("child thread");
}
}
});
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("main thread");
}
}
}

Normal java class vs Anonymous inner class

normal java class: can implement any number of interfaces
anonymous inner class: can implement only one interface at a time.

normal java class: can extend and implement at a same time
anonymous inner class: can either either extend or implement.

normal java class: can write any number of overloaded constructor
anonymous inner class: cant contain any constructor as the class doesnt have any name.

normal java class: if the requirement is standarrd and required several times .
anonymous inner class: if the requirement is temporary and required only once ( instantaneously) then we should go for anonymous inner class.

where are anonymous inner class best suited?
for GUI  based application to implement event handling

4) Static nested classes

Sometimes we can declare inner class with static modifier such type of inner classes are called static nested classes.
in this type there will be chance of existing innerclass without existing outerclass object. static nested class are not strongly associated with outer class.
eg:
public class StaticNested {
static class Nested{
public void m1(){
System.out.println("static nested class");
}
}
public static void main(String[] args) {
Nested n=new Nested();
n.m1();
}
}
if we want to create outside of the class then we can create using
StaticNested.Nested n=new StaticNested.Nested();
n.m1();
in static nested class we can also have static members including main method , hence we can invoke static nested class directly from command prompt.

from static inner class we cant acces non static variables from outer class

difference b/w normal inner class and static nested class

normal inner class: without outer class object there is no chance of inner classs object existence ( stringly associated)
nested static class: without existing outer class object there may be chance of static nested class object 

normal inner class : we cant declare static members in inner class. ( no main method)
nested static class: we can declare static members .(also main method)

normal inner class : we can acces both static and non static members of outer class
nested static class: we can access only static members of outer class.


No comments:

Post a Comment

SOLID principles in java

SOLID  Single responsibility principle : a class should have only  reason to change, i.e. a class should have only one responsibility/single...