Java for Interviews (Core Java - III)

Java for Interviews (Core Java - III)

Core Java - III:

Marker Interface:

  • This is an empty interface (no fields or methods).

  • Serializable, Cloneable, and Remote interfaces are examples of marker interfaces.


Serialization and Deserialization:

Serialization:

  • Process of converting the state of an object into a byte stream after the program exists.

  • This byte stream can be saved as a file (.ser) which is platform-independent.

  • Through this process, the information of the object is saved into the file.

  • Steps to serialize:

    1. Object class should implement a ‘Serializable’ interface.

    2. Use the code below.

       import java.io.serializable;
      
       FileoutputStream fileOut = new FileOutputStream("file path");
       ObjectOutputStream out = new ObjectOutputStream(fileOut);
       out.writeObject(objectName); 
       out.close(); 
       fileOut.close();
      

Deserialization:

  • The reverse process of converting a byte stream into an object.

  • Steps to deserialize:

    1. Create a class same as the one that’s serialized and declare the object (don’t instantiate).

    2. Object class should implement a ‘Serializable’ interface.

    3. Use the code below.

       import java.io.Serializable;
      
       FileInputStream fileIn = new FileInputStream("file path");
       ObjectInputStream in = new ObjectInputStream(fileIn);
       objectName = (<datatype of the object>) in.readObject();
       in.close();
       fileIn.close();
      

Important Notes:

  • Children classes of a parent class that implements ‘Serializable’ will do so as well.

  • Static fields are not serialized. Because they belong to the class itself, and not to an individual object.

  • The class definition itself is not recorded. So while deserializing, cast the input stream as the object type.

  • Fields declared as “transient” aren’t serialized, they’re ignored.

  • SerialVersionUID:

    • Unique ID that functions like a version number.

    • Verifies that the sender and receiver of a serialized object, have loaded classes for that object that match.

    • Ensures objects will be compatible with machines.

    • The number must match, otherwise, this will cause ‘InvalidClassException’.

    • SerialVersionUID will be calculated based on class properties, members, etc...

    • A serializable class can declare its own ‘serialVersionUID’ explicitly (recommended).


Timer and TimerTask:

  • Timer:

    • A facility for threads to schedule tasks for future execution in a background thread.
  • TimerTask:

    • A task that can be scheduled for one-time or repeated execution by a Timer.

Threads:

  • A thread is a lightweight sub-process, the smallest unit of processing.

  • Threads are independent. So, if there occurs an exception in one thread, it doesn’t affect other threads. It uses a shared memory area.

  • Java provides a Thread class to achieve thread programming.

  • JVM allows an application to have multiple threads running concurrently.

  • Each thread can execute parts of the code in parallel with the main thread.

  • Each thread has a priority.

  • Threads with higher priority are executed in preference compared to threads with lower priority.

  • JVM continues to execute threads until either of the following occurs,

    • The exit method of class Runtime has been called.

    • All user threads have died.

  • When a JVM starts up, there is a thread that calls the main method. This thread is called as main.

  • There are two kinds of threads:

    • Daemon thread

    • User thread

  • A Daemon thread is a low-priority thread that runs in the background to perform tasks such as garbage collection.

  • JVM terminates itself when all user threads (non-daemon threads) finish their execution.

  • There are two ways to create threads.

    • Extending the Thread class.

    • Creating an instance of a class that implements the Runnable interface, and passes the instance within the constructor of a Thread class.

    • Example:

        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
            }
        });
      

Multithreading:

  • Process of executing multiple threads simultaneously.

  • Helps maximize utilization of CPU.

  • Threads are independent. So, if there occurs an exception in one thread, it doesn’t affect other threads.

  • Useful for multiple clients, multiplayer games, etc...


Collections Framework:

  • The Collection interface (java.util.Collection) and Map interface (java.util.Map) are the two main root interfaces of java collection classes.

  • Advantages of Collections:

    • Consistent API → The API has a basic set of interfaces like Collection, Set, List, or Map and all the classes like ArrayList, LinkedList, Vector, etc... that implement these interfaces and have some common methods.

    • Reduces programming effort → A developer doesn’t have to worry about the design of the collections.

    • Increases program speed and quality → Increases performance by providing high-performance implementations of useful data structures and algorithms.

  • Hierarchy of the Collection framework:

    • Root interfaces:

      1. Iterable interface:

        • Root interface for the entire collection framework.

        • The collection interface extends the iterable interface.

        • Therefore all the interfaces, and classes implement this interface.

        • This interface provides an iterator to iterate through all the collections.

        • This interface contains only one abstract method which is the iterator.

      2. Collection interface:

        • This interface extends the iterable interface and is implemented by all the classes in the collections framework.

        • This interface contains all the basic methods which every collection has like addition, removing, clearing the data, etc...

        • Having these methods in this interface ensures that the names of the methods are universal for all the collections.

        • This interface builds the foundation on which all the collection classes are implemented.

      3. List interface:

        • This is a child interface of the Collection interface.

        • This interface is dedicated to the data of the list type in which we can store all the ordered collections of the objects.

        • This also allows duplicate data to be present in it.

        • This list interface is implemented by various classes like ArrayList, Vector, Stack, etc.

        • Since all the subclasses implement the list, we can instantiate a list object with any of these classes as shown below.

             List <T> al = new ArrayList<> (); 
             List <T> ll = new LinkedList<> (); 
             List <T> v = new Vector<> ();
          
      4. Queue interface:

        • As the name suggests, a queue interface maintains the FIFO(First In First Out) order similar to a real-world queue line.

        • This interface is dedicated to storing all the elements where the order of the elements matters.

        • There are various classes like PriorityQueue, ArrayDeque, etc.

        • Since all these subclasses implement the queue, we can instantiate a queue object with any of these classes.

            Queue <T> pq = new PriorityQueue<> (); 
            Queue <T> ad = new ArrayDeque<> ();
          
      5. Dequeue interface:

        • This is a very slight variation of the Queue Data Structure.

        • It is also known as a double-ended queue, which is a data structure where we can add and remove the elements from both ends of the queue.

        • This interface extends the queue interface. The class which implements this interface is ArrayDeque.

            Deque<T> ad = new ArrayDeque<> ();
          
      6. Set interface:

        • A set is an unordered collection of objects in which duplicate values cannot be stored.

        • This collection is used when we wish to avoid the duplication of the objects and wish to store only the unique objects.

        • This set interface is implemented by various classes like HashSet, TreeSet, LinkedHashSet, etc.

        • Since all the subclasses implement the set, we can instantiate a set object with any of these classes.

            Set<T> hs = new HashSet<> (); 
            Set<T> lhs = new LinkedHashSet<> (); 
            Set<T> ts = new TreeSet<> ();
          
      7. Sorted Set interface:

        • This interface is very similar to the set interface.

        • The only difference is that this interface has extra methods that maintain the ordering of the elements.

        • The sorted set interface extends the set interface and is used to handle the data which needs to be sorted.

        • The class which implements this interface is TreeSet.

        • Since this class implements the SortedSet, we can instantiate a SortedSet object with this class.

            SortedSet<T> ts = new TreeSet<> ();
          
      8. Map interface:

        • A map is a data structure that supports the key-value pair mapping for the data.

        • This interface doesn’t support duplicate keys because the same key cannot have multiple mappings.

        • A map is useful if there is data and we wish to perform operations based on the key.

        • This map interface is implemented by various classes like HashMap, TreeMap, etc.

        • Since all the subclasses implement the map, we can instantiate a map object with any of these classes.

            Map<T> hm = new HashMap<> (); 
            Map<T> tm = new TreeMap<> ();
          
    • Classes that implement List interface:

      1. ArrayList:

        • ArrayList provides us with dynamic arrays in Java.

        • Though, it may be slower than standard arrays but can be helpful in programs where lots of manipulation in the array is needed.

        • The size of an ArrayList is increased automatically if the collection grows or shrinks when the objects are removed from the collection.

            ArrayList<Integer> al = new ArrayList<Integer>();
          
      2. LinkedList:

        • LinkedList class is an implementation of the LinkedList Data Structure which is a linear data structure where the elements are not stored in contiguous locations and every element is a separate object with a data part and address part.

        • The elements are linked using pointers and addresses.

        • Each element is known as a node.

            LinkedList<Integer> ll = new LinkedList<Integer>();
          
      3. Vector:

        • A vector provides us with dynamic arrays in Java.

        • Though, it may be slower than standard arrays but can be helpful in programs where lots of manipulation in the array is needed.

        • This is identical to ArrayList in terms of implementation.

        • However, the primary difference between a vector and an ArrayList is that a Vector is synchronized and an ArrayList is non-synchronized.

        • Synchronized means only one thread at a time can access the code.

            Vector<Integer> v = new Vector<Integer>();
          
      4. Stack:

        • Stack class models and implements the Stack Data Structure.

        • The class is based on the basic principle of last-in-first-out.

        • In addition to the basic push and pop operations, the class provides three more functions empty, search and peek.

        • This class can also be referred to as the subclass of Vector.

        • Stack is a subclass of Vector and a legacy class. It is thread-safe which might be overhead in an environment where thread safety is not needed. An alternate to Stack is to use ArrayDequeue which is not thread-safe and has faster array implementation.

            Stack<String> stack = new Stack<String>();
          
    • Classes that implement Queue interface:

      1. PriorityQueue:

        • A PriorityQueue is used when the objects are supposed to be processed based on priority.

        • It is known that a queue follows the First-In-First-Out algorithm, but sometimes the elements of the queue are needed to be processed according to the priority and this class is used in these cases.

        • The PriorityQueue is based on the priority heap. The elements of the priority queue are ordered according to the natural ordering, or by a Comparator provided at queue construction time, depending on which constructor is used.

            PriorityQueue<Integer> pQueue = new PriorityQueue<Integer>();
          
    • Classes that implement Deque interface:

      • ArrayDeque class provides us with a way to apply a resizable array.

      • This is a special kind of array that grows and allows users to add or remove an element from both sides of the queue.

      • Array deques have no capacity restrictions and they grow as necessary to support usage.

          ArrayDeque<Integer> de_que = new ArrayDeque<Integer>(10);
        
    • Classes that implement the Set interface:

      1. HashSet:

        • The HashSet class is an inherent implementation of the Hash Table Data Structure.

        • The objects that we insert into the HashSet do not guarantee to be inserted in the same order.

        • The objects are inserted based on their hashcode.

        • This class also allows the insertion of NULL elements.

            HashSet<String> hs = new HashSet<String>();
          
      2. LinkedHashSet:

        • A LinkedHashSet is very similar to a HashSet.

        • The difference is that this uses a doubly linked list to store the data and retains the ordering of the elements.

            LinkedHashSet<String> lhs = new LinkedHashSet<String>();
          
    • Classes that implement the Sorted Set interface:

      1. TreeSet:

        • The TreeSet class uses a Tree for storage.

        • The ordering of the elements is maintained by a set using their natural ordering whether or not an explicit comparator is provided.

        • This must be consistent with equals if it is to correctly implement the Set interface.

        • It can also be ordered by a Comparator provided at a set creation time, depending on which constructor is used.

            TreeSet<String> ts = new TreeSet<String>();
          
    • Classes that implement Map interface:

      1. HashMap:

        • HashMap provides the basic implementation of the Map interface of Java.

        • It stores the data in (Key, Value) pairs.

        • To access a value in a HashMap, we must know its key.

        • HashMap uses a technique called Hashing.

        • Hashing is a technique of converting a large String to a small String that represents the same String so that the indexing and search operations are faster.

        • HashSet also uses HashMap internally.

            HashMap<Integer, String> hm = new HashMap<Integer, String>();
          
      2. TreeMap:

        • The TreeMap in Java has been used to implement Map and NavigableMap interfaces along with the AbstractMap Class.

        • The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.

        • This proves to be an efficient way of sorting and storing the key-value pairs.

        • The storing order maintained by the treemap must be consistent with equals just like any other sorted map, irrespective of the explicit comparators.

        • The treemap implementation is not synchronized in the sense that if a map is accessed by multiple threads, concurrently and at least one of the threads modifies the map structurally, it must be synchronized externally.


Lambda:

  • A lambda expression is a short block of code that takes in parameters and returns a value.

  • Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.

      (n) -> { System.out.println(n); }