Java Interview Quick Notes
Java Interview Quick Notes
Java thread lifecycle includes several states: New, Runnable, Blocked/Waiting, and Terminated. New indicates a thread created but not yet started with 'start()' method. Runnable means the thread is ready for execution and is waiting for the CPU. Blocked or Waiting are states where a thread has paused to wait for a resource or event, while Terminated indicates a completed or dead thread . The 'synchronized' keyword is used to ensure that a method or block of code is accessed by only one thread at a time, preventing data inconsistency during concurrent access. It locks the object for any other thread trying to call a synchronized method or block, thus affecting the runtime behavior of threads by making the necessary code thread-safe .
Design patterns like Singleton and Factory provide proven solutions to common design problems in Java applications. The Singleton pattern ensures a class has only one instance and provides a global point of access to it, which is particularly useful in scenarios like managing shared resources or configurations . The Factory pattern abstracts the creation process, enabling a class to return instances of different classes that share a common interface or superclass. This pattern enhances code reusability, flexibility, and decoupling by allowing object creation to adapt to changing contexts without altering client code, thus supporting the Open/Closed Principle of software design .
In the Java Collections Framework, interfaces define a set of operations that collections can perform. 'List' is used to store ordered sequences of elements allowing duplicates and access by index, exemplified by ArrayList and LinkedList implementations . 'Set', on the other hand, represents a collection that does not allow duplicate elements and does not maintain a particular order, with implementations like HashSet ensuring a constant-time performance for basic operations . 'Map' differs significantly as it represents a collection of key-value pairs and does not extend the Collection interface; keys in a Map are unique, but multiple keys can map to the same value, as seen with HashMap and TreeMap .
Java provides various mechanisms for thread synchronization, primarily through synchronized blocks or methods to lock objects and control access. The 'wait()', 'notify()', and 'notifyAll()' methods belong to the Object class and are used for inter-thread communication via the wait-notify paradigm: a thread in the wait state can be awakened by another thread via 'notify()' or 'notifyAll()' once the condition it's waiting for is met . Conversely, 'sleep()' is a static method of the Thread class and temporarily halts the execution of a thread without releasing its lock, which is useful for pausing execution without involving synchronization . Together, these methods enable coordinated execution and resource sharing among threads, though they require careful management to avoid issues like deadlock .
In Java JDBC, a 'Statement' is used for executing simple SQL queries without parameters, which results in potential SQL injection vulnerabilities and can lead to inefficiencies if the same query is executed multiple times since it isn't precompiled . A 'PreparedStatement', on the other hand, is precompiled on the database server and allows the use of placeholders '?' for input parameters, making it more efficient for repeated execution and providing protection against SQL injection by safely handling input parameters . PreparedStatements are generally preferred for complex queries and for situations requiring secure handling of input data .
Serialization in Java is the process of converting an object's state into a byte stream, thereby allowing for its saving to a file or transfer over a network. Deserialization is the reverse process, transforming the byte stream back into a copy of the object . Typical use cases include saving an object's state for later retrieval, deep cloning, and sending objects between networked applications or components requiring object persistence. Serialization is made possible by implementing the Serializable interface and can be enhanced with custom methods to control which fields are serialized .
Java 8's Streams API provides a higher-level abstraction for processing sequences of elements, such as collections, through a functional-style operation. It can transform and filter data using operations like 'map' for transforming elements and 'filter' for selecting elements based on conditions . For example, one could convert a list of integers to strings and filter those below a certain threshold in a concise chain of operations. Compared to traditional loops, Streams API offers clearer and more readable code, facilitates parallel execution, and enables declarative coding, reducing boilerplate and focusing on what to do rather than how to do it .
Java exceptions are categorized into checked and unchecked exceptions. Checked exceptions are exceptions that are checked at compile-time, such as IOExceptions, requiring methods to handle them with try-catch blocks or declare them with the 'throws' keyword . Unchecked exceptions, such as NullPointerException, occur during runtime and are not subject to mandatory handling at compile time . One should use checked exceptions when the exception might be recoverable or requires proper handling methods, like file operations; unchecked exceptions are suitable for programming errors, like logic flaws, which should not be caught but corrected in the code .
The 'this' keyword in Java is used to refer to the current instance of the class. It can be used to access class variables and methods, and to resolve any shadowing caused by local variables with identical names . On the other hand, the 'super' keyword is used to refer to the superclass (parent class) of the current object. It's primarily used to access methods and constructors of the parent class that have been overridden in the subclass . Thus, while 'this' is concerned with the current class instance, 'super' is about accessing and invoking parent class functionalities.
A HashMap should be preferred over a TreeMap when there is a need for fast insertion, deletion, and lookup operations without the necessity for a particular order of keys, as HashMaps offer average constant-time performance for these operations . In contrast, a TreeMap is ideal if a sorted order of keys is required, as it maintains keys in a naturally ordered state . However, this comes at the cost of slower performance for most operations since TreeMaps provide logarithmic time complexity due to their underlying red-black tree structure .