Java for Interviews (Core Java - I)

Java for Interviews (Core Java - I)

Basics:

JVM, JRE, and JDK:

JVM:

  • JVM (Java Virtual Machine) is an abstract machine that enables your computer to run a Java program.

  • When you run the Java program, the Java compiler first compiles your Java code to bytecode. Then, the JVM translates bytecode into native machine code (a set of instructions that a computer's CPU executes directly).

  • Java is a platform-independent language. It's because when you write Java code, it's ultimately written for JVM but not your physical machine (computer). And JVM can be run on different platforms.

  • JVM is platform-dependent. Because JVM translates the Java bytecode which is platform-independent into machine code on different platforms.

JRE:

  • JRE (Java Runtime Environment) is a software package that provides Java class libraries, Java Virtual Machine (JVM), and other components that are required to run Java applications.

  • JRE is the superset of JVM.

JDK:

  • JDK (Java Development Kit) is a software development kit required to develop applications in Java. When you download JDK, JRE is also downloaded with it.

  • In addition to JRE, JDK also contains several development tools (compilers, JavaDoc, Java Debugger, etc).


JVM Memory Model:

  1. Young Generation:

    • The Young Generation is the place where all the new objects are created.

    • When the young generation is filled, garbage collection is performed. This garbage collection is called Minor GC.

    • Young Generation is divided into three parts - Eden Memory and two Survivor Memory spaces.

    • Important points regarding Young Generation

      • Most of the newly created objects are located in the Eden memory space.

      • When Eden space is filled with objects, Minor GC is performed and all the survivor objects are moved to one of the survivor spaces.

      • Minor GC also checks the survivor objects and moves them to a single survivor space. So at a time, one of the survivor spaces is always empty.

      • Objects that have survived after many cycles of GC are moved to the Old Generation memory space. Usually, it’s done by setting a threshold for the age of the young generation objects before they become eligible to be promoted to Old Generation.

  2. Old Generation:

    • Old Generation memory contains the objects that are long-lived and survived after many rounds of Minor GC.

    • Usually, garbage collection is performed in Old Generation memory when it’s full.

    • Old Generation Garbage Collection is called Major GC and usually takes a longer time.

  3. Permanent Generation:

    • Permanent Generation or “Perm Gen” contains the application metadata required by the JVM to describe the classes and methods used in the application.

    • Note that Perm Gen is not part of Java Heap memory.

    • Perm Gen is populated by JVM at runtime based on the classes used by the application.

    • Perm Gen also contains Java SE library classes and methods.

    • Perm Gen objects are garbage collected in a full garbage collection.

    • Method Area is part of space in the Perm Gen and is used to store class structure (runtime constants and static variables) and code for methods and constructors.


String, StringBuffer, and StringBuilder:

  • The string is immutable whereas StringBuffer and StringBuilder are mutable classes.

  • StringBuffer is thread-safe and synchronized whereas StringBuilder is not.

  • The string concatenation operator (+) internally uses StringBuffer or StringBuilder class.

  • For String manipulations in a multi-threaded environment, we should use the StringBuffer class because it is thread-safe and synchronized.

  • For String manipulations in a single-threaded environment, we should use the StringBuilder class because we don’t have to care about thread safety and synchronization.

  • As StringBuilder is not thread-safe and not synchronized, the performance is greater and the memory it uses is also low when compared to StringBuffer.

  • Example StringBuffer vs StringBuilder performance:

      import java.util.GregorianCalendar;
    
      public class TestString {
    
          public static void main(String[] args) {
              System.gc();
              long start=new GregorianCalendar().getTimeInMillis();
              long startMemory=Runtime.getRuntime().freeMemory();
              StringBuffer sb = new StringBuffer();
              //StringBuilder sb = new StringBuilder();
              for(int i = 0; i<10000000; i++){
                  sb.append(":").append(i);
              }
              long end=new GregorianCalendar().getTimeInMillis();
              long endMemory=Runtime.getRuntime().freeMemory();
              System.out.println("Time Taken:"+(end-start));
              System.out.println("Memory used:"+(startMemory-endMemory));
          }
      }
    

Core Java - I (OOPs):

Objects:

  • The instances that can be instantiated from a particular class are called objects.

  • An object is any entity that has a state and behavior.

  • These properties and behaviors are implemented by methods inside the class from which the objects are instantiated.

  • Objects are stored in Heap Space and their reference is stored in Stack Memory.


Class:

  • Class is a user-defined blueprint or prototype from which objects can be instantiated.

  • Class is a logical entity of a physical object.

Inner Class:

  • An inner class or nested class is a class that is declared inside another class or interface.

  • Inner classes are used to logically group classes and interfaces in one place to be more readable and maintainable.

  • Inner classes can access all the members of the outer class, including the private data members and methods.

  • There are two types of inner classes:

    1. Static nested class → A static class created within a class.

      • Example:

          class Animal {
        
          // inner class
             class Reptile {
                public void displayInfo() {
                  System.out.println("I am a reptile.");
                }
             }
        
          // static class
             static class Mammal {
                public void displayInfo() {
                  System.out.println("I am a mammal.");
                }
             }
          }
        
          class Main {
             public static void main(String[] args) {
                // object creation of the outer class
                Animal animal = new Animal();
        
                // object creation of the non-static class
                Animal.Reptile reptile = animal.new Reptile();
                reptile.displayInfo();
        
                // object creation of the static nested class
                Animal.Mammal mammal = new Animal.Mammal();
                mammal.displayInfo();
        
             }
          }
        
    2. Non-static nested class → This is called an Inner class. Instances of the inner class have access to all the methods and attributes of the outer class.

      • Local inner class → Inner class defined inside a method.

      • Anonymous inner class → A class created for implementing an interface or extending a class. Java compiler decides its name.

      • Member inner class → A class created within class and outside method.

Abstract Class and Method:

  • The abstract class in Java cannot be instantiated (we cannot create objects of abstract classes).

  • An abstract class can have both regular methods and abstract methods.

  • A method that doesn't have its body is known as an abstract method. We use the same abstract keyword to create abstract methods.

  • If a class contains an abstract method, then the class should be declared abstract. Otherwise, it will generate an error.

  • Though abstract classes cannot be instantiated, we can create subclasses from them. We can then access members of the abstract class using the object of the subclass.

  • Example:

      abstract class Language {
    
        // method of abstract class
        public void display() {
          System.out.println("This is Java Programming");
        }
      }
    
      class Main extends Language {
    
        public static void main(String[] args) {
    
          // create an object of Main
          Main obj = new Main();
    
          // access method of abstract class
          // using object of Main class
          obj.display();
        }
      }
    

Interface:

  • An interface is a fully abstract class.

  • Interfaces are classes that contain method signatures without a body which can be implemented in other classes.

  • By using interfaces, we can share common methods by overriding them.

  • Interfaces are used to implement abstraction.

  • Example:

      interface Polygon {
        void getArea(int length, int breadth);
      }
    
      // implement the Polygon interface
      class Rectangle implements Polygon {
    
        // implementation of abstract method
        public void getArea(int length, int breadth) {
          System.out.println("The area of the rectangle is " + (length * breadth));
        }
      }
    
      class Main {
        public static void main(String[] args) {
          Rectangle r1 = new Rectangle();
          r1.getArea(5, 6);
        }
      }
    

Abstraction:

  • In Java, Data Abstraction is defined as the process of reducing the object to its essence so that only the necessary characteristics are exposed to the users.

  • Abstraction defines an object in terms of its properties (attributes), behavior (methods), and interfaces (means of communicating with other objects).


Encapsulation:

  • Wrapping the data (variables) and code acting on those data (methods) together as a single unit.

  • The variables of a class will be hidden from other classes and can be accessed only through the methods of their current class.

  • This is also called Data Hiding.

  • Example:

      class Area {
    
        // fields to calculate area
        int length;
        int breadth;
    
        // constructor to initialize values
        Area(int length, int breadth) {
          this.length = length;
          this.breadth = breadth;
        }
    
        // method to calculate area
        public void getArea() {
          int area = length * breadth;
          System.out.println("Area: " + area);
        }
      }
    
      class Main {
        public static void main(String[] args) {
    
          // create object of Area
          // pass value of length and breadth
          Area rectangle = new Area(5, 6);
          rectangle.getArea();
        }
      }
    

Inheritance:

  • Creating new classes, by building upon existing classes are called inheritance.

  • This way the new classes can access the attributes and methods of the existing class.

  • The existing class is called the parent class, and the new class will be called the child class.

  • In Java, inheritance is an is-a relationship. That is, we use inheritance only if there exists an is-a relationship between two classes. [e.g] Car is a Vehicle.

  • In Java, if a class includes protected fields and methods, then these fields and methods are accessible from the subclass of the class.

  • Example:

      class Animal {
    
        // field and method of the parent class
        String name;
        public void eat() {
          System.out.println("I can eat");
        }
      }
    
      // inherit from Animal
      class Dog extends Animal {
    
        // new method in subclass
        public void display() {
          System.out.println("My name is " + name);
        }
      }
    
      class Main {
        public static void main(String[] args) {
    
          // create an object of the subclass
          Dog labrador = new Dog();
    
          // access field of superclass
          labrador.name = "Rohu";
          labrador.display();
    
          // call method of superclass
          // using object of subclass
          labrador.eat();
    
        }
      }
    

Types of Inheritance:

  1. Single Inheritance:

    • In single inheritance, a single subclass extends from a single superclass.

  2. Multi-level Inheritance:

    • In multilevel inheritance, a subclass extends from a superclass and then the same subclass acts as a superclass for another class.

  3. Hierarchical Inheritance:

    • In hierarchical inheritance, multiple subclasses extend from a single superclass.

  4. Multiple Inheritance:

    • In multiple inheritances, a single subclass extends from multiple superclasses.

    • Java doesn't support multiple inheritances. However, we can achieve multiple inheritances using interfaces.

  5. Hybrid Inheritance:

    • Hybrid inheritance is a combination of two or more types of inheritance.


Polymorphism:

  • The word polymorphism means many forms. The ability of a message to be displayed in more than one form is called polymorphism. There are two types of polymorphism.

    • Compile Time polymorphism:

      • It is also known as static polymorphism.

      • This type of polymorphism is achieved by method overloading.

    • Run Time polymorphism:

      • It is also known as Dynamic Method Dispatch.

      • It is a process in which a function call to the overridden method is resolved at runtime.

      • This type of polymorphism is achieved by Method Overriding.